choron_support 0.1.9 → 0.1.11
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/.rubocop.yml +138 -6
- data/.rubocop_todo.yml +1 -0
- data/CHANGELOG.md +11 -3
- data/Gemfile.lock +1 -1
- data/README.md +2 -6
- data/choron_support.gemspec +8 -7
- data/docs/props.md +17 -217
- data/lib/choron_support/as_props.rb +34 -24
- data/lib/choron_support/domain_delegate.rb +1 -3
- data/lib/choron_support/helper.rb +7 -9
- data/lib/choron_support/props/attributes.rb +186 -349
- data/lib/choron_support/props/base.rb +12 -26
- data/lib/choron_support/props/ext/hash.rb +1 -1
- data/lib/choron_support/props/ext/relation.rb +1 -1
- data/lib/choron_support/props/private/setting.rb +40 -0
- data/lib/choron_support/queries/base.rb +1 -1
- data/lib/choron_support/scope_query.rb +3 -3
- data/lib/choron_support/set_mask_for.rb +5 -5
- data/lib/choron_support/version.rb +1 -1
- data/lib/choron_support.rb +7 -1
- metadata +15 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4ed418bdccc564f3988b17a0fe5571d7e7bde690de9381b7e562e9866b4cbf3a
|
4
|
+
data.tar.gz: 476fe2f299614945830acea6a253a630dab27b45250cb04c5b60d9dbe14cc831
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 716153850aa6324f6ad3619b83d9f27694ee9c1a8cea669ecd73e37e0f29212bd5ef9cae7871e3046aac80d55054fef17200dfe48de9a6c8a18c7b0ac3a955a7
|
7
|
+
data.tar.gz: 3a68ee8bcfa75ff86b99abd97da1dc662ba7d832b36e1cc56e8d3cd6c9f70dd905886a95f71e94fb32fa2fb86776e8398612a9eef8db9172c31fb0cde1a8b1b6
|
data/.rubocop.yml
CHANGED
@@ -1,13 +1,145 @@
|
|
1
|
+
# 参考
|
2
|
+
# * デフォルト値の設定ファイル
|
3
|
+
# https://github.com/rubocop/rubocop/blob/master/config/default.yml
|
4
|
+
inherit_from: .rubocop_todo.yml
|
5
|
+
|
1
6
|
AllCops:
|
2
|
-
TargetRubyVersion:
|
7
|
+
TargetRubyVersion: 3.1.3
|
8
|
+
# Rubocop更新時に新しいルールがあれば適用する
|
9
|
+
NewCops: enable
|
10
|
+
# 使用しているgemに対して拡張ツールを提案してくれるか。
|
11
|
+
# 特に不要(そこまでrubocopに頼っていないため)
|
12
|
+
SuggestExtensions: false
|
13
|
+
Exclude:
|
14
|
+
# デフォルトの設定
|
15
|
+
- "vendor/**/*"
|
16
|
+
- "node_modules/**/*"
|
17
|
+
# テストファイルは対象外にしています
|
18
|
+
- "spec/**/*"
|
19
|
+
# 設定ファイルは特に変更することがないため
|
20
|
+
- "config/**/*"
|
21
|
+
# スクリプトファイルは除外(プロダクトとは関係ないため)
|
22
|
+
- "scripts/**/*"
|
23
|
+
# bin系はあまり変更することがないため
|
24
|
+
- "bin/**/*"
|
3
25
|
|
26
|
+
# ドキュメントの無い public class は許可
|
27
|
+
Style/Documentation:
|
28
|
+
Enabled: false
|
29
|
+
# 空のメソッドを許可
|
30
|
+
Style/EmptyMethod:
|
31
|
+
Enabled: false
|
32
|
+
# if 内での個別変数代入を許可
|
33
|
+
Style/ConditionalAssignment:
|
34
|
+
Enabled: false
|
35
|
+
# else 内での if の許可
|
36
|
+
Style/IfInsideElse:
|
37
|
+
Enabled: false
|
38
|
+
# bad: [1,2,3].map { _1.to_s }, good: [1,2,3].map(&:to_s)
|
39
|
+
# _1.xxx のほうが読みやすいことが多いので false に変更しています
|
40
|
+
Style/SymbolProc:
|
41
|
+
Enabled: false
|
42
|
+
# 空の else を許可
|
43
|
+
Style/EmptyElse:
|
44
|
+
Enabled: false
|
45
|
+
# 1行の場合に後置ifの強制を許可
|
46
|
+
Style/IfUnlessModifier:
|
47
|
+
Enabled: false
|
48
|
+
# not禁止を許可
|
49
|
+
Style/Not:
|
50
|
+
Enabled: false
|
51
|
+
# ガード句の強制を許可
|
52
|
+
Style/GuardClause:
|
53
|
+
Enabled: false
|
54
|
+
# if文等の空ブロックを許可
|
55
|
+
Lint/EmptyConditionalBody:
|
56
|
+
Enabled: false
|
57
|
+
# 使い分けが面倒なのでダブルで統一
|
4
58
|
Style/StringLiterals:
|
5
|
-
Enabled: true
|
6
59
|
EnforcedStyle: double_quotes
|
60
|
+
# Hashやメソッドの階層化はスペース分だけ
|
61
|
+
Layout/FirstHashElementIndentation:
|
62
|
+
EnforcedStyle: consistent
|
7
63
|
|
8
|
-
|
9
|
-
|
10
|
-
|
64
|
+
Metrics/ModuleLength:
|
65
|
+
Max: 400
|
66
|
+
Metrics/BlockLength:
|
67
|
+
Max: 100
|
68
|
+
Metrics/AbcSize:
|
69
|
+
Max: 65
|
70
|
+
Metrics/ClassLength:
|
71
|
+
Max: 300
|
72
|
+
Metrics/CyclomaticComplexity:
|
73
|
+
Max: 30
|
74
|
+
Metrics/PerceivedComplexity:
|
75
|
+
Max: 30
|
11
76
|
|
12
77
|
Layout/LineLength:
|
13
|
-
Max:
|
78
|
+
Max: 200
|
79
|
+
Layout/TrailingEmptyLines:
|
80
|
+
Enabled: false
|
81
|
+
Layout/HashAlignment:
|
82
|
+
Enabled: false
|
83
|
+
|
84
|
+
# クラスとモジュール名を分けて記載するかどうか
|
85
|
+
# 検索容易性を加味してfalseにする
|
86
|
+
Style/ClassAndModuleChildren:
|
87
|
+
Enabled: false
|
88
|
+
|
89
|
+
# frozen literal をコメントで書くかどうか
|
90
|
+
# Ruby3系からデフォルトtrueなのでfalseにする
|
91
|
+
Style/FrozenStringLiteralComment:
|
92
|
+
Enabled: false
|
93
|
+
|
94
|
+
# 1行の長さ。基本長くてもOK
|
95
|
+
# Layout/LineLength:
|
96
|
+
# Max: 300
|
97
|
+
|
98
|
+
# メソッド名の長さ
|
99
|
+
# わかりやすさ重視とするので長さは考慮しない
|
100
|
+
Metrics/MethodLength:
|
101
|
+
Enabled: false
|
102
|
+
|
103
|
+
# Hashの最後の項目にカンマを許すかどうか
|
104
|
+
# カンマあったほうが便利なのでfalse
|
105
|
+
Style/TrailingCommaInHashLiteral:
|
106
|
+
Enabled: false
|
107
|
+
Style/TrailingCommaInArguments:
|
108
|
+
Enabled: false
|
109
|
+
Style/TrailingCommaInArrayLiteral:
|
110
|
+
Enabled: false
|
111
|
+
|
112
|
+
# ブロックコメントを許可するかどうか
|
113
|
+
# 使ってもいいではないかということで許可
|
114
|
+
Style/BlockComments:
|
115
|
+
Enabled: false
|
116
|
+
|
117
|
+
# self. をつけたほうがわかりやすいときもあるのでfalse(可読性重視)
|
118
|
+
Style/RedundantSelf:
|
119
|
+
Enabled: false
|
120
|
+
|
121
|
+
# 大文字の時点で定数と読み取れるので無理にmutableにしなくても良い
|
122
|
+
Style/MutableConstant:
|
123
|
+
Enabled: false
|
124
|
+
|
125
|
+
# _つきのメソッドを内部メソッドとしてはやすことがあるため
|
126
|
+
Naming/VariableNumber:
|
127
|
+
Enabled: false
|
128
|
+
|
129
|
+
# unless よりも if のほうが見やすいときがあるため
|
130
|
+
Style/NegatedIf:
|
131
|
+
Enabled: false
|
132
|
+
|
133
|
+
# _ 始まりの変数を許可するか
|
134
|
+
# スコープの狭い変数として利用することがあるため許可する
|
135
|
+
Lint/UnderscorePrefixedVariableName:
|
136
|
+
Enabled: false
|
137
|
+
|
138
|
+
# get とか set という名前のついたメソッドを許可するか
|
139
|
+
# DSL的なものを利用するときに利用することもあるため許可する
|
140
|
+
Naming/AccessorMethodName:
|
141
|
+
Enabled: false
|
142
|
+
|
143
|
+
# DSL的なものを使うためパラメータは7個まで許可
|
144
|
+
Metrics/ParameterLists:
|
145
|
+
Max: 7
|
data/.rubocop_todo.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# 必要に応じて記載していってください
|
data/CHANGELOG.md
CHANGED
@@ -2,14 +2,22 @@
|
|
2
2
|
|
3
3
|
## [0.1.0] - 2022-12-04
|
4
4
|
|
5
|
-
|
5
|
+
- Initial release
|
6
6
|
|
7
7
|
## [0.1.8] - 2023-06-04
|
8
8
|
|
9
9
|
### `as_props`
|
10
10
|
|
11
|
-
|
11
|
+
- もしPropsクラスが見つからなかった場合にエラーをraiseするように修正
|
12
12
|
|
13
13
|
### `set_mask_for`
|
14
14
|
|
15
|
-
|
15
|
+
- マスク処理のAPIを提供開始
|
16
|
+
|
17
|
+
## [0.1.11] - 2024-08-24
|
18
|
+
|
19
|
+
- `Props` の改善を実施
|
20
|
+
- `STI` のサポートを追加
|
21
|
+
- `only` や `except` で既存のPropsの一部の値だけを利用できるように修正
|
22
|
+
- `Domain` の改善を実施
|
23
|
+
- `!` で終わるメソッドもデリゲートできるように修正
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -25,13 +25,9 @@ ChoronSupport.using :all
|
|
25
25
|
|
26
26
|
* 必要に応じて各種モジュールをincludeすることで利用できます
|
27
27
|
|
28
|
-
###
|
29
|
-
|
30
|
-
モデルをJSON(キーがローキャメルケース)に変換するための仕組みです。
|
31
|
-
|
32
|
-
* 詳細な使い方は [テストファイル](./spec/choron_support/as_props_spec.rb) を参照ください。
|
33
|
-
* 詳細な実装は [こちら](./lib/choron_support/as_props.rb) です。
|
28
|
+
### Props
|
34
29
|
|
30
|
+
* [Props ドキュメント](./docs/props.md)を参照ください
|
35
31
|
|
36
32
|
### Mask
|
37
33
|
|
data/choron_support.gemspec
CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
|
|
12
12
|
spec.description = "By using this library, you can incorporate some useful functions into Ruby on Rails."
|
13
13
|
spec.homepage = "https://github.com/mksava/choron_support"
|
14
14
|
spec.license = "MIT"
|
15
|
-
spec.required_ruby_version = ">=
|
15
|
+
spec.required_ruby_version = ">= 3.1"
|
16
16
|
|
17
17
|
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
18
18
|
|
@@ -34,17 +34,18 @@ Gem::Specification.new do |spec|
|
|
34
34
|
# Uncomment to register a new dependency of your gem
|
35
35
|
spec.add_dependency "activesupport"
|
36
36
|
spec.add_development_dependency "activerecord"
|
37
|
-
spec.add_development_dependency "
|
37
|
+
spec.add_development_dependency "factory_bot_rails"
|
38
38
|
spec.add_development_dependency "mysql2"
|
39
|
+
spec.add_development_dependency "pry-byebug"
|
40
|
+
spec.add_development_dependency "pry-rails"
|
41
|
+
spec.add_development_dependency "ridgepole"
|
42
|
+
spec.add_development_dependency "rspec-parameterized"
|
43
|
+
spec.add_development_dependency "simplecov"
|
39
44
|
spec.add_development_dependency "spring"
|
40
45
|
spec.add_development_dependency "spring-commands-rspec"
|
41
|
-
spec.add_development_dependency "pry-rails"
|
42
|
-
spec.add_development_dependency "pry-byebug"
|
43
46
|
spec.add_development_dependency "yard"
|
44
|
-
spec.add_development_dependency "factory_bot_rails"
|
45
|
-
spec.add_development_dependency "simplecov"
|
46
|
-
spec.add_development_dependency "rspec-parameterized"
|
47
47
|
|
48
48
|
# For more information and examples about making a new gem, check out our
|
49
49
|
# guide at: https://bundler.io/guides/creating_gem.html
|
50
|
+
spec.metadata["rubygems_mfa_required"] = "true"
|
50
51
|
end
|
data/docs/props.md
CHANGED
@@ -11,225 +11,25 @@ Choronでは画面側の処理をReact + Typescrip の組み合わせで実現
|
|
11
11
|
一般的なJSON化ツールの違いとしては、Javascript側の記法・慣習を優先するため、
|
12
12
|
JSONのキーをローキャメルケース(fullName, isAdult,など)に自動変換します
|
13
13
|
|
14
|
-
##
|
14
|
+
## 使い方
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
* ChoronSupport::Props::Attributes
|
21
|
-
の2つのクラス・モジュールを継承&includedしたProps用の基底クラスを用意しています。
|
22
|
-
|
23
|
-
```app/models/props/base.rb
|
24
|
-
class Props::Base < ChoronSupport::Props::Base
|
25
|
-
include ChoronSupport::Props::Attributes
|
26
|
-
end
|
27
|
-
```
|
28
|
-
|
29
|
-
そして以下の命名ルールにより、モデルごとのPropsクラスを作成しています
|
30
|
-
* app/models/props/${モデル名}.rb
|
31
|
-
* 例: app/models/props/user.rb
|
32
|
-
これは ChoronSupport::AsProps モジュールがモデル名から自動で props/**/*.rb を探し出してインスタンスを生成してくれる処理に由来します。
|
33
|
-
|
34
|
-
```app/models/props/user.rb
|
35
|
-
class Props::Foo < Props::Base
|
36
|
-
attributes :id, :name, :full_name
|
37
|
-
attributes :full_name, to: :self
|
38
|
-
def full_name
|
39
|
-
"#{model.first_name} #{model.last_name}"
|
40
|
-
end
|
41
|
-
end
|
42
|
-
```
|
43
|
-
|
44
|
-
これで準備は完了です。
|
45
|
-
以下のようにController等で利用ができます
|
46
|
-
|
47
|
-
```app/controllers/users_controller.rb
|
48
|
-
class UsersController < ApplicationController
|
49
|
-
def index
|
50
|
-
users = User.all
|
51
|
-
props = {
|
52
|
-
users: users.as_props
|
53
|
-
}
|
54
|
-
|
55
|
-
render react_file(props: props)
|
56
|
-
end
|
57
|
-
|
58
|
-
def show
|
59
|
-
user = User.find(params[:id])
|
60
|
-
props = {
|
61
|
-
user: user.as_props
|
62
|
-
}
|
63
|
-
|
64
|
-
render react_file(props: props)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
```
|
68
|
-
|
69
|
-
サンプルコードからわかるように `#as_props` というメソッドはモデルおよびRelationの両方で利用が可能なように拡張をしています。
|
70
|
-
|
71
|
-
この拡張を使うためには ChoronSupport::AsProps モジュールを ApplicationRecord にinclude する必要があります。
|
72
|
-
|
73
|
-
Choronではすでに実施済です。
|
74
|
-
|
75
|
-
```app/models/application_record.rb
|
76
|
-
class ApplicationRecord < ActiveRecord::Base
|
77
|
-
include ChoronSupport::AsProps
|
78
|
-
end
|
79
|
-
```
|
80
|
-
|
81
|
-
もしPropsクラスをわざわざ作らず、モデルのカラムをそのまま全てローキャメルケースで出したい時もあると思います。そのときは
|
82
|
-
|
83
|
-
```
|
84
|
-
user.as_props(:model)
|
85
|
-
```
|
86
|
-
|
87
|
-
と第一引数で `:model` を渡すことで、カラム全てをprops化します。
|
88
|
-
※これは個人情報など思わぬ値も出力してしまう可能性もあるため、安全な処理にだけ使うことを推奨します
|
89
|
-
|
90
|
-
また、キーワード引数を使うことでパラメーターを渡すことも可能です。
|
91
|
-
これを利用すれば、Props側を利用する側から細かいPropsの出力調整ができます。
|
92
|
-
|
93
|
-
```app/models/props/foo.rb
|
94
|
-
class Props::Foo < Props::Base
|
95
|
-
attributes :id, :name
|
96
|
-
attributes :full_name, if: :show_name?
|
97
|
-
def show_name?
|
98
|
-
# #params で as_props 実行時のキーワード引数にアクセスができる
|
99
|
-
params[:show_name].present?
|
100
|
-
end
|
101
|
-
end
|
102
|
-
```
|
103
|
-
|
104
|
-
これは以下のように利用できます
|
105
|
-
|
106
|
-
```
|
107
|
-
foo = Foo.find(1)
|
108
|
-
foo.as_props(show_name: true)
|
109
|
-
```
|
110
|
-
|
111
|
-
また、この `DSL` を使うことで以下の情報がメタ情報として自動的に出力されます。
|
112
|
-
* type: Props化を行なったクラスの名前(名前空間あり)
|
113
|
-
* modelName: Props化を行なったモデルの名前(名前空間なし)
|
114
|
-
|
115
|
-
```app/models/props/foos/bar.rb
|
116
|
-
class Props::Foos::Bar < Props::Base
|
117
|
-
attributes :id, :name
|
16
|
+
```ruby
|
17
|
+
class Props::Samples::Foo < Props::Base
|
18
|
+
attribute :id
|
19
|
+
attribute :full_name
|
118
20
|
end
|
119
|
-
```
|
120
|
-
|
121
|
-
Foos::Bar.new.as_props
|
122
|
-
#=> { id: x, name: "xxx", type: "Foos::Bar", modelName: "Bar" }
|
123
|
-
|
124
|
-
もし `RAILS_ENV=test` のときはさらに Props化を行なったクラスもメタ情報として付与されます。
|
125
|
-
|
126
|
-
Foos::Bar.new.as_props
|
127
|
-
#=> { id: x, name: "xxx", type: "Foos::Bar", modelName: "Bar", propsClassName: "Props::Foos::Bar" }
|
128
|
-
|
129
|
-
このメタ情報を使うことでテストの簡略化も可能となります。
|
130
|
-
|
131
|
-
例えば Controller のテストを以下のように書くことができます。
|
132
|
-
|
133
|
-
```spec/requests/foos_controller_spec.rb
|
134
|
-
describe FoosController, type: :request do
|
135
|
-
describe "GET /foos/:id" do
|
136
|
-
let!(:id) { foo.id }
|
137
|
-
let!(:foo) { create(:foo) }
|
138
|
-
it "詳細画面が表示されること" do
|
139
|
-
is_expected.to eq 200
|
140
|
-
|
141
|
-
react = rendered_react("foo/show")
|
142
|
-
props = react.props
|
143
|
-
# 細かい値の設定はProps側の単体テストで担保しているため、ここでは使われているPropsのみ検証する
|
144
|
-
expect(props[:foo][:propsClassName]).to eq "Props::Foos::Bar"
|
145
|
-
# Choron では専用のマッチャーがあるため以下のように記載も可能
|
146
|
-
expect(props[:foo]).to be_use_props(Props::Foos::Bar)
|
147
|
-
end
|
148
|
-
end
|
149
|
-
end
|
150
|
-
```
|
151
|
-
|
152
|
-
### DSLの細かい使い方
|
153
|
-
* ChoronSupport::Props::Attributesのソースコードを参照ください
|
154
|
-
* https://github.com/mksava/choron_support/blob/main/lib/choron_support/props/attributes.rb
|
155
|
-
|
156
|
-
### Propsの設計思想
|
157
|
-
ChoronでのPropsはattributesのDSLでif文の指定が可能です。
|
158
|
-
そうでなくてもpropsメソッドをオーバーライドすることでさらに細かい調整が可能です。
|
159
|
-
|
160
|
-
しかしPropsの設計思想は「1つのPropsで複数のパターンのJSONを作成する」よりも「複数のパターンがある分、Propsクラスを作成する」にあります。
|
161
|
-
|
162
|
-
たとえば「User」には個人情報が含まれいるため、Propsの出力を制御したいときは
|
163
|
-
|
164
|
-
* 一般的な利用
|
165
|
-
* `app/models/props/user.rb`
|
166
|
-
* スタッフなど個人情報にアクセス可能なユーザからの利用
|
167
|
-
* `app/models/props/users/staff.rb`
|
168
|
-
* ログインしているユーザ自身が自分自身の情報を見たいときに利用
|
169
|
-
* `app/models/props/users/current.rb`
|
170
|
-
|
171
|
-
というようにPropsクラスを複数作成することを検討してください。
|
172
|
-
このとき、各Propsクラスは以下のように `#as_props` の第一引数を指定することで利用できます
|
173
|
-
|
174
|
-
```
|
175
|
-
# app/models/props/users/general.rb
|
176
|
-
users = Users.all.as_props(:general)
|
177
|
-
# app/models/props/users/staff.rb
|
178
|
-
users = Users.all.as_props(:staff)
|
179
|
-
# app/models/props/users/current.rb
|
180
|
-
users = Users.all.as_props(:current)
|
181
|
-
```
|
182
|
-
|
183
|
-
## サンプルコード
|
184
|
-
|
185
|
-
* Props を作成するときはこのサンプルコードを優先的に参考にしてください
|
186
|
-
* Sample の部分は適宜作成したいモデル名に変更してください
|
187
|
-
|
188
|
-
### ActiveRecord
|
189
|
-
|
190
|
-
```app/models/sample.rb
|
191
|
-
class Sample < ApplicationRecord
|
192
|
-
end
|
193
|
-
```
|
194
|
-
|
195
|
-
```app/controllers/samples_controller.rb
|
196
|
-
class SamplesController < ApplicationController
|
197
|
-
def index
|
198
|
-
samples = Sample.all
|
199
|
-
props = {
|
200
|
-
samples: samples.as_props(:general)
|
201
|
-
}
|
202
|
-
|
203
|
-
render react_file(props: props)
|
204
|
-
end
|
205
|
-
end
|
206
|
-
```
|
207
|
-
|
208
|
-
```app/models/props/sample.rb
|
209
|
-
class Props::Sample < Props::Base
|
210
|
-
attributes :id, :name, :created_at, :updated_at
|
211
|
-
attributes :is_sample?, to: :self
|
212
21
|
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
end
|
22
|
+
sample = Sample.new(id: 100, full_name: "mksava")
|
23
|
+
sample.as_props(:foo)
|
24
|
+
#=> { id: 100, fullName: "mksava", type: "Foo", modelName: "Foo" }
|
217
25
|
```
|
218
26
|
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
```
|
229
|
-
|
230
|
-
```app/models/props/samples/staff.rb
|
231
|
-
class Props::Samples::Staff < Props::Base
|
232
|
-
self.union = :default
|
233
|
-
attributes :salary
|
234
|
-
end
|
235
|
-
```
|
27
|
+
* 詳細な使い方はテストファイルを参照ください。
|
28
|
+
* [一般的な使い方](../spec/choron_support/as_props/general_spec.rb)
|
29
|
+
* [エッジケース](../spec/choron_support/as_props/edge_spec.rb)
|
30
|
+
* [attribute DSLの使い方](../spec/choron_support/as_props/attribute_spec.rb)
|
31
|
+
* [inherit DSL の使い方](../spec/choron_support/as_props/inherit_spec.rb)
|
32
|
+
* [relation DSLの使い方](../spec/choron_support/as_props/relation_spec.rb)
|
33
|
+
* 実装は以下を参照ください
|
34
|
+
* [as_props.rb](../lib/choron_support/as_props.rb)
|
35
|
+
* [props/](../lib/choron_support/props/)
|
@@ -5,40 +5,53 @@ require_relative "props/ext/hash"
|
|
5
5
|
module ChoronSupport
|
6
6
|
module AsProps
|
7
7
|
class NameError < StandardError; end
|
8
|
+
|
8
9
|
# @param [Symbol, String, nil] type_symbol どのPropsクラスを利用してPropsを生成するかを指定するシンボル。nilのときはデフォルトのPropsクラスを利用する。
|
9
|
-
# @param [Hash] params
|
10
|
+
# @param [Hash] params その他のパラメータ
|
11
|
+
# @param [Hash] params params[:camel] false を指定すると自動でキャメライズしない。
|
12
|
+
# @param [Hash] params params[:only] 指定した属性のみを出力します
|
13
|
+
# @param [Hash] params params[:except] 指定した属性を出力しません
|
14
|
+
# @param [Hash] params params[:sti] true を指定すると継承クラスのPropsを利用する
|
10
15
|
# @return [Hash]
|
11
16
|
def as_props(type_symbol = nil, **params)
|
12
|
-
|
17
|
+
pass_params = params.except(:camel, :sti)
|
13
18
|
|
19
|
+
serializer = __get_props_class(type_symbol, pass_params, sti: params[:sti])
|
14
20
|
skip_camel = (params[:camel] == false)
|
15
|
-
pass_params = params.except(:camel)
|
16
21
|
if serializer.nil?
|
17
|
-
skip_camel ?
|
22
|
+
skip_camel ? as_json : as_json.as_camel
|
18
23
|
else
|
19
|
-
skip_camel ? serializer.as_props
|
24
|
+
skip_camel ? serializer.as_props : serializer.as_props.as_camel
|
20
25
|
end
|
21
26
|
end
|
22
27
|
|
23
28
|
private
|
24
29
|
|
25
|
-
def __get_props_class(type_symbol, params)
|
30
|
+
def __get_props_class(type_symbol, params, sti:)
|
26
31
|
case type_symbol
|
27
32
|
when Symbol, String
|
28
|
-
|
29
|
-
|
30
|
-
|
33
|
+
model_namespace = if sti
|
34
|
+
# STIのときは継承クラスのPropsを利用する
|
35
|
+
self.class.superclass.to_s.pluralize
|
36
|
+
else
|
37
|
+
self.class.to_s.pluralize
|
38
|
+
end
|
39
|
+
# 名前空間の例: Props::Users, Props::RealEstates::Buildings
|
40
|
+
namespace = "Props::#{model_namespace}"
|
41
|
+
# クラス名の例: :common => Common, :foo_bar => FooBar
|
31
42
|
class_name = type_symbol.to_s.classify
|
32
|
-
# 例:
|
33
|
-
props_class_name = "#{namespace}::#{class_name}"
|
34
|
-
when nil
|
35
|
-
namespace = "Props"
|
36
|
-
# 例: User / Master::Plan
|
37
|
-
class_name = self.class.to_s
|
38
|
-
# 例: Props::User
|
43
|
+
# 例: Props::Users::Common, Props::RealEstates::Buildings::FooBar
|
39
44
|
props_class_name = "#{namespace}::#{class_name}"
|
45
|
+
when Class
|
46
|
+
# Classが渡されているときはそのまま利用する
|
47
|
+
given_class = type_symbol
|
48
|
+
unless given_class.method_defined?(:as_props)
|
49
|
+
raise ArgumentError, "invalid class: #{given_class}, must be respond to :as_props. self: #{self.class}"
|
50
|
+
end
|
51
|
+
|
52
|
+
props_class_name = given_class.to_s
|
40
53
|
else
|
41
|
-
raise ArgumentError
|
54
|
+
raise ArgumentError, "invalid type_symbol: #{type_symbol.inspect}. self: #{self.class}"
|
42
55
|
end
|
43
56
|
|
44
57
|
begin
|
@@ -46,15 +59,12 @@ module ChoronSupport
|
|
46
59
|
|
47
60
|
props_class.new(self, params)
|
48
61
|
rescue *rescue_errors
|
49
|
-
# もしmodelを指定しているときはnilを返し、as_jsonを利用させる
|
50
|
-
if type_symbol == :model
|
51
|
-
return nil
|
52
|
-
end
|
53
|
-
|
54
62
|
if type_symbol.blank?
|
55
|
-
raise ChoronSupport::AsProps::NameError,
|
63
|
+
raise ChoronSupport::AsProps::NameError,
|
64
|
+
"Props class not found: #{props_class_name}. Please create props class. self: #{self.class}"
|
56
65
|
else
|
57
|
-
raise ChoronSupport::AsProps::NameError,
|
66
|
+
raise ChoronSupport::AsProps::NameError,
|
67
|
+
"Props class not found: #{props_class_name}. Got type symbol: #{type_symbol}. self: #{self.class}"
|
58
68
|
end
|
59
69
|
end
|
60
70
|
end
|
@@ -35,7 +35,7 @@ module ChoronSupport
|
|
35
35
|
|
36
36
|
# 被ることがないようにど__をつけてメソッド名を定義します
|
37
37
|
# 例: :__domains_users_purchase_object__
|
38
|
-
domain_object_method_name =
|
38
|
+
domain_object_method_name = "__#{domain_class.to_s.underscore.gsub('/', '_')}_object__".to_sym
|
39
39
|
|
40
40
|
define_method(domain_object_method_name) do
|
41
41
|
# ドメインオブジェクトをインスタンス化したものを返します
|
@@ -83,8 +83,6 @@ module ChoronSupport
|
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
86
|
-
private
|
87
|
-
|
88
86
|
def self.__generate_choron_domain_class(method_symbol, specific, class_name)
|
89
87
|
# クラス名指定なしのときはメソッド名からクラスを推測する
|
90
88
|
if class_name.to_s.empty?
|
@@ -5,21 +5,19 @@ module ChoronSupport
|
|
5
5
|
class << self
|
6
6
|
def generate_choron_class(namespaces, model_name, class_symbol, exception: true)
|
7
7
|
# 命名規則に従いQueryクラスを自動で探して scope を設定する
|
8
|
-
namespace =
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
end
|
14
|
-
end
|
8
|
+
namespace = if namespaces.is_a?(Array)
|
9
|
+
namespaces.join("::")
|
10
|
+
else
|
11
|
+
namespaces.to_s
|
12
|
+
end
|
15
13
|
|
16
14
|
unless model_name.to_s.empty?
|
17
15
|
namespace = "#{namespaces}::#{model_name.pluralize}"
|
18
16
|
end
|
19
17
|
|
20
18
|
target_class_name = "#{namespace}::#{class_symbol.to_s.camelize}"
|
21
|
-
# ? 終わりはクラスに変換できないため
|
22
|
-
if target_class_name.end_with?("?")
|
19
|
+
# ? や ! 終わりはクラスに変換できないため
|
20
|
+
if target_class_name.end_with?("?") || target_class_name.end_with?("!")
|
23
21
|
target_class_name.chop!
|
24
22
|
end
|
25
23
|
|