rails-settings-cached 2.1.1 → 2.3.3

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: f952983987531a930ac0f603d37aed4938648f4e858297182b4039987fc6c975
4
- data.tar.gz: ecbfbf363e6c67519ced21e25966ebb0339bc7dae2e3171d95ab2d04675b5b7e
3
+ metadata.gz: d9fb44e09bad24a4d3c6cf36fda107fe18ce214964b713de318e5f3efc083851
4
+ data.tar.gz: 75ee5df473cff1fc07b963b6441152f559de8d0a5652267530c5c0f62cac93f9
5
5
  SHA512:
6
- metadata.gz: d78651e359e244a155e1e743dd391494f0792504b816dc8bd0d3cdbfd1d7103a16c020895f7b751007f5f5b3a04d4d94398e5a7df4cc09ad07ff1166b0d05ed2
7
- data.tar.gz: 2320d0950d5a9b9090f5b5df27f42df1b7a74553104e584728146ac5cd41cd567b58e450e9121dc764be4c534209d988b2b1b516b1e948913806f1b4c5850961
6
+ metadata.gz: 6bf0b841b4b2ee46b7da5f51a54d2e3f17f984f2fe1f72841bc056966efc29fd5ad70ea54b0b5559f4ea493927ef796cbc956302b404e18ec61059c40d620904
7
+ data.tar.gz: 76a594a2df28a1490c6d67b1fff1a4d776572cc1240c9c07549d6d0349c048a017ee10f828d7c38e41bdf4c7158af9108f9c9181af3ee015af72654cd23831ff
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- ## Rails Settings Cached
1
+ # Rails Settings Cached
2
2
 
3
3
  This a plugin that makes managing a table of
4
4
  а global key, value pairs easy. Think of it like a global Hash stored in your database,
@@ -6,39 +6,23 @@ that uses simple ActiveRecord like methods for manipulation. Keep track of any g
6
6
  setting that you don't want to hard code into your rails app. You can store any kind
7
7
  of object. Strings, numbers, arrays, or any object.
8
8
 
9
- > 🚨 BREAK CHANGES WARNING:
10
- > rails-settings-cached 2.x has redesigned the API, the new version will compatible with the stored setting values by an older version.
11
- > When you want to upgrade 2.x, you must read the README again, and follow guides to change your Setting model.
12
- > 0.x stable branch: https://github.com/huacnlee/rails-settings-cached/tree/0.x
9
+ [![Gem Version](https://badge.fury.io/rb/rails-settings-cached.svg)](https://rubygems.org/gems/rails-settings-cached) [![CI Status](https://travis-ci.org/huacnlee/rails-settings-cached.svg)](http://travis-ci.org/huacnlee/rails-settings-cached) [![codecov.io](https://codecov.io/github/huacnlee/rails-settings-cached/coverage.svg?branch=master)](https://codecov.io/github/huacnlee/rails-settings-cached?branch=master)
13
10
 
14
- ## Status
15
-
16
- [![Gem Version](https://badge.fury.io/rb/rails-settings-cached.svg)](https://rubygems.org/gems/rails-settings-cached) [![CI Status](https://travis-ci.org/huacnlee/rails-settings-cached.svg)](http://travis-ci.org/huacnlee/rails-settings-cached) [![Code Climate](https://codeclimate.com/github/huacnlee/rails-settings-cached/badges/gpa.svg)](https://codeclimate.com/github/huacnlee/rails-settings-cached) [![codecov.io](https://codecov.io/github/huacnlee/rails-settings-cached/coverage.svg?branch=master)](https://codecov.io/github/huacnlee/rails-settings-cached?branch=master)
17
-
18
- ## Setup
11
+ ## Installation
19
12
 
20
13
  Edit your Gemfile:
21
14
 
22
- ```ruby
23
- gem "rails-settings-cached", "~> 2.0"
24
- ```
25
-
26
- Generate your settings:
27
-
28
15
  ```bash
29
- $ rails g settings:install
16
+ $ bundle add rails-settings-cached
30
17
  ```
31
18
 
32
- If you want custom model name:
19
+ Generate your settings:
33
20
 
34
21
  ```bash
35
22
  $ rails g settings:install
36
- ```
37
23
 
38
- Or use a custom name:
39
-
40
- ```bash
41
- $ rails g settings:install SiteConfig
24
+ # Or use a custom name:
25
+ $ rails g settings:install AppConfig
42
26
  ```
43
27
 
44
28
  You will get `app/models/setting.rb`
@@ -46,19 +30,26 @@ You will get `app/models/setting.rb`
46
30
  ```rb
47
31
  class Setting < RailsSettings::Base
48
32
  # cache_prefix { "v1" }
49
-
50
- field :host, default: "http://example.com"
33
+ field :app_name, default: "Rails Settings"
34
+ field :host, default: "http://example.com", readonly: true
35
+ field :default_locale, default: "zh-CN"
51
36
  field :readonly_item, type: :integer, default: 100, readonly: true
52
37
  field :user_limits, type: :integer, default: 20
38
+ field :exchange_rate, type: :float, default: 0.123
53
39
  field :admin_emails, type: :array, default: %w[admin@rubyonrails.org]
40
+ field :captcha_enable, type: :boolean, default: true
41
+
54
42
  # Override array separator, default: /[\n,]/ split with \n or comma.
55
43
  field :tips, type: :array, separator: /[\n]+/
56
- field :captcha_enable, type: :boolean, default: 1
44
+
57
45
  field :notification_options, type: :hash, default: {
58
46
  send_all: true,
59
47
  logging: true,
60
48
  sender_email: "foo@bar.com"
61
49
  }
50
+
51
+ # lambda default value
52
+ field :welcome_message, type: :string, default: -> { "welcome to #{self.app_name}" }
62
53
  end
63
54
  ```
64
55
 
@@ -67,19 +58,21 @@ You must use `field` method to statement the setting keys, otherwise you can't u
67
58
  Now just put that migration in the database with:
68
59
 
69
60
  ```bash
70
- rake db:migrate
61
+ $ rails db:migrate
71
62
  ```
72
63
 
73
64
  ## Usage
74
65
 
75
- The syntax is easy. First, let's create some settings to keep track of:
66
+ The syntax is easy. First, let's create some settings to keep track of:
76
67
 
77
68
  ```ruby
78
69
  irb > Setting.host
79
70
  "http://example.com"
80
- irb > Setting.host = "https://your-host.com"
81
- irb > Setting.host
82
- "https://your-host.com"
71
+ irb > Setting.app_name
72
+ "Rails Settings"
73
+ irb > Setting.app_name = "Rails Settings Cached"
74
+ irb > Setting.app_name
75
+ "Rails Settings Cached"
83
76
 
84
77
  irb > Setting.user_limits
85
78
  20
@@ -133,6 +126,31 @@ irb > Setting.notification_options
133
126
  }
134
127
  ```
135
128
 
129
+
130
+ ### Get defined fields
131
+
132
+ > version 2.3+
133
+
134
+ ```rb
135
+ # Get all keys
136
+ Setting.keys
137
+ => ["app_name", "host", "default_locale", "readonly_item"]
138
+
139
+ # Get editable keys
140
+ Settng.editable_keys
141
+ => ["app_name", "default_locale"]
142
+
143
+ # Get readonly keys
144
+ Setting.readonly_keys
145
+ => ["host", "readonly_item"]
146
+
147
+ # Get options of field
148
+ Setting.get_field("host")
149
+ => { key: "host", type: :string, default: "http://example.com", readonly: true }
150
+ Setting.get_field("app_name")
151
+ => { key: "app_name", type: :string, default: "Rails Settings", readonly: false }
152
+ ```
153
+
136
154
  ## Readonly field
137
155
 
138
156
  Sometimes you may need to use Setting before Rails is initialized, for example `config/devise.rb`
@@ -200,7 +218,7 @@ config/routes.rb
200
218
 
201
219
  ```rb
202
220
  namespace :admin do
203
- resources :settings
221
+ resource :settings
204
222
  end
205
223
  ```
206
224
 
@@ -212,18 +230,13 @@ module Admin
212
230
  class SettingsController < ApplicationController
213
231
  before_action :get_setting, only: [:edit, :update]
214
232
 
215
- def show
216
- end
217
-
218
233
  def create
219
234
  setting_params.keys.each do |key|
220
- next if key.to_s == "site_logo"
221
235
  Setting.send("#{key}=", setting_params[key].strip) unless setting_params[key].nil?
222
236
  end
223
- redirect_to admin_settings_path(notice: "Setting was successfully updated.")
237
+ redirect_to settings_path, notice: "Setting was successfully updated."
224
238
  end
225
239
 
226
-
227
240
  private
228
241
  def setting_params
229
242
  params.require(:setting).permit(:host, :user_limits, :admin_emails,
@@ -259,80 +272,52 @@ app/views/admin/settings/show.html.erb
259
272
  <%= f.text_area :notification_options, value: YAML.dump(Setting.notification_options), class: "form-control", style: "height: 180px;" %>
260
273
  <div class="form-text">
261
274
  Use YAML format to config the SMTP_html
262
- </details>
263
- <% end %>
264
- ```
265
-
266
- ## Backward compatible to support 0.x scoped settings
267
-
268
- You may used the scoped setting feature in 0.x version. Before you upgrade rails-settings-cached 2.x, you must follow this guide to backward compatible it.
269
-
270
- For example:
271
-
272
- ```rb
273
- class User < ApplicationRecord
274
- include RailsSettings::Extend
275
- end
275
+ </div>
276
+ </div>
276
277
 
277
- @user.settings.color = "red"
278
- @user.settings.foo = 123
278
+ <div>
279
+ <%= f.submit 'Update Settings' %>
280
+ </div>
281
+ <% end %>
279
282
  ```
280
283
 
281
- create `app/models/concerns/scoped_setting.rb`
284
+ ## Scoped Settings
282
285
 
283
- ```rb
284
- module ScopedSetting
285
- extend ActiveSupport::Concern
286
+ > 🚨 BREAK CHANGES WARNING:
287
+ > rails-settings-cached 2.x has redesigned the API, the new version will compatible with the stored setting values by an older version.
288
+ > When you want to upgrade 2.x, you must read the README again, and follow guides to change your Setting model.
289
+ > 0.x stable branch: https://github.com/huacnlee/rails-settings-cached/tree/0.x
286
290
 
287
- included do
288
- has_many :settings, as: :thing
289
- end
291
+ - [Backward compatible to support 0.x scoped settings](docs/backward-compatible-to-scoped-settings.md)
290
292
 
291
- class_methods do
292
- def scoped_field(name, default: nil)
293
- define_method(name) do
294
- obj = settings.where(var: name).take || settings.new(var: name, value: default)
295
- obj.value
296
- end
293
+ For new project / new user of rails-settings-cached. The [ActiveRecord::AttributeMethods::Serialization](https://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/Serialization/ClassMethods.html#method-i-serialize) is best choice.
297
294
 
298
- define_method("#{name}=") do |val|
299
- record = settings.where(var: name).take || settings.new(var: name)
300
- record.value = val
301
- record.save!
295
+ > This is reason of why rails-settings-cached 2.x removed **Scoped Settings** feature.
302
296
 
303
- val
304
- end
305
- end
306
- end
307
- end
308
- ```
297
+ For example:
309
298
 
310
- Now include it for your model:
299
+ We wants a preferences setting for user.
311
300
 
312
301
  ```rb
313
- class User < ApplicationRecord
314
- include ScopedSetting
315
-
316
- scoped_field :color, default: ""
317
- scoped_field :foo, default: 0
302
+ class User < ActiveRecord::Base
303
+ serialize :preferences
318
304
  end
319
- ```
320
-
321
- Now you must to find project with ".setting." for replace with:
322
305
 
323
- Same values will fetch from the `settings` table.
324
-
325
- ```rb
326
- @user.color = "red"
327
- @user.color # => "red"
328
- @user.foo = 123
329
- @user.foo # =>
306
+ @user = User.new
307
+ @user.preferences[:receive_emails] = true
308
+ @user.preferences[:public_email] = true
309
+ @user.save
330
310
  ```
331
311
 
332
312
  ## Use cases:
333
313
 
334
- - [ruby-china/ruby-china](https://github.com/ruby-china/ruby-china)
335
- - [thebluedoc/bluedoc](https://github.com/thebluedoc/bluedoc/blob/master/app/models/setting.rb)
336
- - [tootsuite/mastodon](https://github.com/tootsuite/mastodon)
337
- - [helpyio/helpy](https://github.com/helpyio/helpy)
314
+ - [ruby-china/homeland](https://github.com/ruby-china/homeland) - master
315
+ - [forem/forem](https://github.com/forem/forem) - 2.x
316
+ - [siwapp/siwapp](https://github.com/siwapp/siwapp) - 2.x
317
+ - [aidewoode/black_candy](https://github.com/aidewoode/black_candy) - 2.x
318
+ - [thebluedoc/bluedoc](https://github.com/thebluedoc/bluedoc/blob/master/app/models/setting.rb) - 2.x
319
+ - [tootsuite/mastodon](https://github.com/tootsuite/mastodon) - 0.6.x
320
+ - [helpyio/helpy](https://github.com/helpyio/helpy) - 0.5.x
321
+
338
322
 
323
+ And more than [1K repositories](https://github.com/huacnlee/rails-settings-cached/network/dependents) used.
@@ -3,14 +3,15 @@
3
3
  require "rails/generators"
4
4
  require "rails/generators/migration"
5
5
 
6
- module Settings
6
+ module RailsSettings
7
7
  class InstallGenerator < Rails::Generators::NamedBase
8
+ namespace "settings:install"
8
9
  desc "Generate RailsSettings files."
9
10
  include Rails::Generators::Migration
10
11
 
11
12
  argument :name, type: :string, default: "setting"
12
13
 
13
- source_root File.expand_path("../templates", __FILE__)
14
+ source_root File.expand_path("templates", __dir__)
14
15
 
15
16
  @@migrations = false
16
17
 
@@ -6,7 +6,7 @@ module RailsSettings
6
6
  class Base < ActiveRecord::Base
7
7
  class SettingNotFound < RuntimeError; end
8
8
 
9
- SEPARATOR_REGEXP = /[\n,]+/
9
+ SEPARATOR_REGEXP = /[\n,;]+/.freeze
10
10
  self.table_name = table_name_prefix + "settings"
11
11
 
12
12
  # get the value field, YAML decoded
@@ -26,13 +26,17 @@ module RailsSettings
26
26
  class << self
27
27
  def clear_cache
28
28
  RequestStore.store[:rails_settings_all_settings] = nil
29
- Rails.cache.delete(self.cache_key)
29
+ Rails.cache.delete(cache_key)
30
30
  end
31
31
 
32
32
  def field(key, **opts)
33
33
  _define_field(key, default: opts[:default], type: opts[:type], readonly: opts[:readonly], separator: opts[:separator])
34
34
  end
35
35
 
36
+ def get_field(key)
37
+ @defined_fields.find { |field| field[:key] == key.to_s } || {}
38
+ end
39
+
36
40
  def cache_prefix(&block)
37
41
  @cache_prefix = block
38
42
  end
@@ -43,88 +47,126 @@ module RailsSettings
43
47
  scope.join("/")
44
48
  end
45
49
 
46
- private
47
- def _define_field(key, default: nil, type: :string, readonly: false, separator: nil)
48
- if readonly
49
- define_singleton_method(key) do
50
- self.send(:_covert_string_to_typeof_value, type, default, separator: separator)
51
- end
52
- else
53
- define_singleton_method(key) do
54
- val = self.send(:_value_of, key)
55
- result = nil
56
- if !val.nil?
57
- result = val
58
- else
59
- result = default
60
- result = default.call if default.is_a?(Proc)
61
- end
62
-
63
- result = self.send(:_covert_string_to_typeof_value, type, result, separator: separator)
64
-
65
- result
66
- end
50
+ def keys
51
+ @defined_fields.map { |field| field[:key] }
52
+ end
67
53
 
68
- define_singleton_method("#{key}=") do |value|
69
- var_name = key.to_s
54
+ def editable_keys
55
+ @defined_fields.reject { |field| field[:readonly] }.map { |field| field[:key] }
56
+ end
70
57
 
71
- record = find_by(var: var_name) || new(var: var_name)
72
- value = self.send(:_covert_string_to_typeof_value, type, value, separator: separator)
58
+ def readonly_keys
59
+ @defined_fields.select { |field| field[:readonly] }.map { |field| field[:key] }
60
+ end
73
61
 
74
- record.value = value
75
- record.save!
62
+ private
76
63
 
77
- value
78
- end
64
+ def _define_field(key, default: nil, type: :string, readonly: false, separator: nil)
65
+ @defined_fields ||= []
66
+ @defined_fields << {
67
+ key: key.to_s,
68
+ default: default,
69
+ type: type || :string,
70
+ readonly: readonly.nil? ? false : readonly
71
+ }
72
+
73
+ if readonly
74
+ define_singleton_method(key) do
75
+ send(:_convert_string_to_typeof_value, type, default, separator: separator)
79
76
  end
80
-
81
- if type == :boolean
82
- define_singleton_method("#{key}?") do
83
- self.send(key)
77
+ else
78
+ define_singleton_method(key) do
79
+ val = send(:_value_of, key)
80
+ result = nil
81
+ if !val.nil?
82
+ result = val
83
+ else
84
+ result = default
85
+ result = default.call if default.is_a?(Proc)
84
86
  end
87
+
88
+ result = send(:_convert_string_to_typeof_value, type, result, separator: separator)
89
+
90
+ result
85
91
  end
86
- end
87
92
 
88
- def _covert_string_to_typeof_value(type, value, separator: nil)
89
- return value unless value.is_a?(String) || value.is_a?(Integer)
90
-
91
- case type
92
- when :boolean
93
- return value == "true" || value == "1" || value == 1 || value == true
94
- when :array
95
- return value.split(separator || SEPARATOR_REGEXP).reject { |str| str.empty? }
96
- when :hash
97
- value = YAML.load(value).to_hash rescue {}
98
- value.deep_stringify_keys!
99
- return value
100
- when :integer
101
- return value.to_i
102
- else
93
+ define_singleton_method("#{key}=") do |value|
94
+ var_name = key.to_s
95
+
96
+ record = find_by(var: var_name) || new(var: var_name)
97
+ value = send(:_convert_string_to_typeof_value, type, value, separator: separator)
98
+
99
+ record.value = value
100
+ record.save!
101
+
103
102
  value
104
103
  end
105
104
  end
106
105
 
107
- def _value_of(var_name)
108
- raise "#{self.table_name} does not exist." unless table_exists?
106
+ if type == :boolean
107
+ define_singleton_method("#{key}?") do
108
+ send(key)
109
+ end
110
+ end
111
+ end
109
112
 
110
- _all_settings[var_name.to_s]
113
+ def _convert_string_to_typeof_value(type, value, separator: nil)
114
+ return value unless [String, Integer, Float, BigDecimal].include?(value.class)
115
+
116
+ case type
117
+ when :boolean
118
+ value == "true" || value == "1" || value == 1 || value == true
119
+ when :array
120
+ value.split(separator || SEPARATOR_REGEXP).reject { |str| str.empty? }.map(&:strip)
121
+ when :hash
122
+ value = begin
123
+ begin
124
+ YAML.load(value).to_h
125
+ rescue StandardError
126
+ eval(value).to_h
127
+ end
128
+ rescue StandardError
129
+ {}
130
+ end
131
+ value.deep_stringify_keys!
132
+ ActiveSupport::HashWithIndifferentAccess.new(value)
133
+ when :integer
134
+ value.to_i
135
+ when :float
136
+ value.to_f
137
+ when :big_decimal
138
+ value.to_d
139
+ else
140
+ value
111
141
  end
142
+ end
112
143
 
113
- def rails_initialized?
114
- Rails.application && Rails.application.initialized?
144
+ def _value_of(var_name)
145
+ unless table_exists?
146
+ # Fallback to default value if table was not ready (before migrate)
147
+ puts "WARNING: table: \"#{table_name}\" does not exist, `#{name}.#{var_name}` fallback to returns the default value."
148
+ return nil
115
149
  end
116
150
 
117
- def _all_settings
118
- raise "You cannot use settings before Rails initialize." unless rails_initialized?
119
- RequestStore.store[:rails_settings_all_settings] ||= begin
120
- Rails.cache.fetch(self.cache_key, expires_in: 1.week) do
121
- vars = unscoped.select("var, value")
122
- result = {}
123
- vars.each { |record| result[record.var] = record.value }
124
- result.with_indifferent_access
125
- end
151
+ _all_settings[var_name.to_s]
152
+ end
153
+
154
+ def rails_initialized?
155
+ Rails.application&.initialized?
156
+ end
157
+
158
+ def _all_settings
159
+ raise "You cannot use settings before Rails initialize." unless rails_initialized?
160
+
161
+ RequestStore.store[:rails_settings_all_settings] ||= begin
162
+ Rails.cache.fetch(cache_key, expires_in: 1.week) do
163
+ vars = unscoped.select("var, value")
164
+ result = {}
165
+ vars.each { |record| result[record.var] = record.value }
166
+ result.with_indifferent_access
126
167
  end
127
168
  end
169
+ end
128
170
  end
129
171
  end
130
172
  end
@@ -3,7 +3,7 @@
3
3
  module RailsSettings
4
4
  class << self
5
5
  def version
6
- "2.1.1"
6
+ "2.3.3"
7
7
  end
8
8
  end
9
9
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails-settings-cached
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.1
4
+ version: 2.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jason Lee
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-10-07 00:00:00.000000000 Z
11
+ date: 2020-10-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -39,7 +39,7 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: sqlite3
42
+ name: codecov
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
@@ -53,7 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: rubocop
56
+ name: minitest
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -67,7 +67,7 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: simplecov
70
+ name: rubocop
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - ">="
@@ -81,7 +81,7 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: minitest
84
+ name: simplecov
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - ">="
@@ -95,7 +95,7 @@ dependencies:
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
- name: codecov
98
+ name: sqlite3
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - ">="
@@ -130,9 +130,10 @@ files:
130
130
  - lib/rails-settings/railtie.rb
131
131
  - lib/rails-settings/version.rb
132
132
  homepage: https://github.com/huacnlee/rails-settings-cached
133
- licenses: []
133
+ licenses:
134
+ - MIT
134
135
  metadata: {}
135
- post_install_message:
136
+ post_install_message:
136
137
  rdoc_options: []
137
138
  require_paths:
138
139
  - lib
@@ -148,7 +149,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
148
149
  version: '0'
149
150
  requirements: []
150
151
  rubygems_version: 3.0.3
151
- signing_key:
152
+ signing_key:
152
153
  specification_version: 4
153
154
  summary: Settings plugin for Rails that makes managing a table of global keys.
154
155
  test_files: []