sparrow-entity 0.2.0 → 0.3.0
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 +2 -0
- data/.ruby-version +1 -1
- data/Gemfile.lock +80 -53
- data/README.ja.md +256 -0
- data/README.md +189 -85
- data/README.zh-CN.md +256 -0
- data/lib/sparrow/version.rb +1 -1
- data/sparrow.gemspec +2 -1
- metadata +7 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: be3bce43bdbd1c4380323c6ad8e4fcdbfe88d029fbfa2a5fad1301a209e7446e
|
|
4
|
+
data.tar.gz: d22a24207c474a06d218432a22e7ced31e3d5b2c1c3629326a242d66757f3069
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6b37e180508398470f90083690b52a02066e49af868a7a74d6fc27122defd39a5ae137e54081193319ed16ddf6a59da447212e7a7563d53163fc7d0914a4783b
|
|
7
|
+
data.tar.gz: 85174be39093adb300d35779f0d04de33315e7aee9c952e0ca631a631bce151974ddce5c4faed3c0266e3cc3ba3400572ff679f866e2234042b7b293c4ca67c9
|
data/.rubocop.yml
CHANGED
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
ruby-2.
|
|
1
|
+
ruby-2.7.7
|
data/Gemfile.lock
CHANGED
|
@@ -1,84 +1,111 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
sparrow-entity (0.
|
|
4
|
+
sparrow-entity (0.3.0)
|
|
5
5
|
activemodel
|
|
6
|
-
activemodel_object_info (
|
|
6
|
+
activemodel_object_info (>= 0.4.2)
|
|
7
7
|
activesupport
|
|
8
8
|
|
|
9
9
|
GEM
|
|
10
10
|
remote: https://rubygems.org/
|
|
11
11
|
specs:
|
|
12
|
-
activemodel (
|
|
13
|
-
activesupport (=
|
|
14
|
-
activemodel_object_info (0.2
|
|
12
|
+
activemodel (7.1.6)
|
|
13
|
+
activesupport (= 7.1.6)
|
|
14
|
+
activemodel_object_info (0.4.2)
|
|
15
15
|
activesupport
|
|
16
|
-
activesupport (
|
|
16
|
+
activesupport (7.1.6)
|
|
17
|
+
base64
|
|
18
|
+
benchmark (>= 0.3)
|
|
19
|
+
bigdecimal
|
|
17
20
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
21
|
+
connection_pool (>= 2.2.5)
|
|
22
|
+
drb
|
|
18
23
|
i18n (>= 1.6, < 2)
|
|
24
|
+
logger (>= 1.4.2)
|
|
19
25
|
minitest (>= 5.1)
|
|
26
|
+
mutex_m
|
|
27
|
+
securerandom (>= 0.3)
|
|
20
28
|
tzinfo (~> 2.0)
|
|
21
|
-
|
|
22
|
-
|
|
29
|
+
ast (2.4.3)
|
|
30
|
+
base64 (0.3.0)
|
|
31
|
+
benchmark (0.5.0)
|
|
32
|
+
bigdecimal (4.1.2)
|
|
23
33
|
coderay (1.1.3)
|
|
24
|
-
concurrent-ruby (1.
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
34
|
+
concurrent-ruby (1.3.8)
|
|
35
|
+
connection_pool (2.5.5)
|
|
36
|
+
diff-lcs (1.6.2)
|
|
37
|
+
docile (1.4.1)
|
|
38
|
+
drb (2.2.3)
|
|
39
|
+
i18n (1.14.8)
|
|
28
40
|
concurrent-ruby (~> 1.0)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
41
|
+
io-console (0.8.2)
|
|
42
|
+
json (2.21.1)
|
|
43
|
+
language_server-protocol (3.17.0.6)
|
|
44
|
+
lint_roller (1.1.0)
|
|
45
|
+
logger (1.7.0)
|
|
46
|
+
method_source (1.1.0)
|
|
47
|
+
minitest (5.26.1)
|
|
48
|
+
mutex_m (0.3.0)
|
|
49
|
+
parallel (1.28.0)
|
|
50
|
+
parser (3.3.12.0)
|
|
33
51
|
ast (~> 2.4.1)
|
|
34
|
-
|
|
52
|
+
racc
|
|
53
|
+
prism (1.9.0)
|
|
54
|
+
pry (0.16.0)
|
|
35
55
|
coderay (~> 1.1)
|
|
36
56
|
method_source (~> 1.0)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
rspec-
|
|
47
|
-
|
|
57
|
+
reline (>= 0.6.0)
|
|
58
|
+
racc (1.8.1)
|
|
59
|
+
rainbow (3.1.1)
|
|
60
|
+
rake (13.4.2)
|
|
61
|
+
regexp_parser (2.12.0)
|
|
62
|
+
reline (0.6.3)
|
|
63
|
+
io-console (~> 0.5)
|
|
64
|
+
rspec (3.13.2)
|
|
65
|
+
rspec-core (~> 3.13.0)
|
|
66
|
+
rspec-expectations (~> 3.13.0)
|
|
67
|
+
rspec-mocks (~> 3.13.0)
|
|
68
|
+
rspec-core (3.13.6)
|
|
69
|
+
rspec-support (~> 3.13.0)
|
|
70
|
+
rspec-expectations (3.13.5)
|
|
48
71
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
49
|
-
rspec-support (~> 3.
|
|
50
|
-
rspec-mocks (3.
|
|
72
|
+
rspec-support (~> 3.13.0)
|
|
73
|
+
rspec-mocks (3.13.8)
|
|
51
74
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
52
|
-
rspec-support (~> 3.
|
|
53
|
-
rspec-support (3.
|
|
54
|
-
rubocop (1.
|
|
55
|
-
|
|
56
|
-
|
|
75
|
+
rspec-support (~> 3.13.0)
|
|
76
|
+
rspec-support (3.13.7)
|
|
77
|
+
rubocop (1.88.2)
|
|
78
|
+
json (~> 2.3)
|
|
79
|
+
language_server-protocol (~> 3.17.0.2)
|
|
80
|
+
lint_roller (~> 1.1.0)
|
|
81
|
+
parallel (>= 1.10)
|
|
82
|
+
parser (>= 3.3.0.2)
|
|
57
83
|
rainbow (>= 2.2.2, < 4.0)
|
|
58
|
-
regexp_parser (>=
|
|
59
|
-
|
|
60
|
-
rubocop-ast (>= 1.15.0, < 2.0)
|
|
84
|
+
regexp_parser (>= 2.9.3, < 3.0)
|
|
85
|
+
rubocop-ast (>= 1.49.0, < 2.0)
|
|
61
86
|
ruby-progressbar (~> 1.7)
|
|
62
|
-
unicode-display_width (>=
|
|
63
|
-
rubocop-ast (1.
|
|
64
|
-
parser (>= 3.
|
|
65
|
-
|
|
66
|
-
|
|
87
|
+
unicode-display_width (>= 2.4.0, < 4.0)
|
|
88
|
+
rubocop-ast (1.50.0)
|
|
89
|
+
parser (>= 3.3.7.2)
|
|
90
|
+
prism (~> 1.7)
|
|
91
|
+
ruby-progressbar (1.13.0)
|
|
92
|
+
securerandom (0.3.2)
|
|
93
|
+
simplecov (0.22.0)
|
|
67
94
|
docile (~> 1.1)
|
|
68
95
|
simplecov-html (~> 0.11)
|
|
69
96
|
simplecov_json_formatter (~> 0.1)
|
|
70
|
-
simplecov-html (0.
|
|
71
|
-
simplecov_json_formatter (0.1.
|
|
72
|
-
tzinfo (2.0.
|
|
97
|
+
simplecov-html (0.13.2)
|
|
98
|
+
simplecov_json_formatter (0.1.4)
|
|
99
|
+
tzinfo (2.0.6)
|
|
73
100
|
concurrent-ruby (~> 1.0)
|
|
74
|
-
unicode-display_width (2.
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
zeitwerk (2.5.3)
|
|
101
|
+
unicode-display_width (3.2.0)
|
|
102
|
+
unicode-emoji (~> 4.1)
|
|
103
|
+
unicode-emoji (4.2.0)
|
|
104
|
+
yard (0.9.45)
|
|
79
105
|
|
|
80
106
|
PLATFORMS
|
|
81
|
-
|
|
107
|
+
arm64-darwin-21
|
|
108
|
+
arm64-darwin-22
|
|
82
109
|
|
|
83
110
|
DEPENDENCIES
|
|
84
111
|
bundler
|
|
@@ -91,4 +118,4 @@ DEPENDENCIES
|
|
|
91
118
|
yard
|
|
92
119
|
|
|
93
120
|
BUNDLED WITH
|
|
94
|
-
|
|
121
|
+
2.4.10
|
data/README.ja.md
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
# 🐦 Sparrow Entity
|
|
2
|
+
|
|
3
|
+
[English](./README.md) | [简体中文](./README.zh-CN.md) | [日本語](./README.ja.md)
|
|
4
|
+
|
|
5
|
+
[](https://rubygems.org/gems/sparrow-entity)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
## 📖 目次
|
|
9
|
+
- [🌟 概要](#-概要)
|
|
10
|
+
- [✨ 主な機能](#-主な機能)
|
|
11
|
+
- [📦 インストール](#-インストール)
|
|
12
|
+
- [💻 使い方ガイド](#-使い方ガイド)
|
|
13
|
+
- [1. 基本的なエンティティの定義](#1-基本的なエンティティの定義)
|
|
14
|
+
- [2. 自動型変換](#2-自動型変換)
|
|
15
|
+
- [3. 真偽値(Boolean)フィールド](#3-真偽値booleanフィールド)
|
|
16
|
+
- [4. デフォルト値](#4-デフォルト値)
|
|
17
|
+
- [5. ActiveModel の統合(バリデーションとコールバック)](#5-activemodel-の統合バリデーションとコールバック)
|
|
18
|
+
- [6. シリアライズ](#6-シリアライズ)
|
|
19
|
+
- [🚀 Rails 統合とジェネレーター](#-rails-統合とジェネレーター)
|
|
20
|
+
- [📝 ライセンス](#-ライセンス)
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 🌟 概要
|
|
25
|
+
|
|
26
|
+
**Sparrow Entity** は、データベースに依存しないデータに対して、ORMライクなエンティティモデリングを提供する軽量な Ruby Gem です。
|
|
27
|
+
|
|
28
|
+
現代のアーキテクチャ、特にマイクロサービスでは、ローカルデータベースではなく外部 API、メッセージキュー、または gRPC サービスから大量のデータを取得して処理することがよくあります。このようなシナリオでは、背後にデータベーステーブルが存在しないため、`ActiveRecord::Base` を使用することができません。**Sparrow** はこのギャップを完全に埋め、使い慣れた ActiveModel の利便性を保ちながら、構造化され強力に型付けされたエンティティオブジェクト(強化された PORO)を定義できるようにします。
|
|
29
|
+
|
|
30
|
+
## ✨ 主な機能
|
|
31
|
+
|
|
32
|
+
* **🛠 ORMライクな操作感**:ActiveRecord と同じように属性と型を定義できます。
|
|
33
|
+
* **🗂 自動型変換**:代入された値を定義済みの型(例:`String`、`Integer`、`Date`、`Sparrow::Boolean`)に自動的に変換します。
|
|
34
|
+
* **⚙️ デフォルト値**:初期化時の値が空または無効な場合に備えて、属性にデフォルトのフォールバック値を設定できます。
|
|
35
|
+
* **🛤 ActiveModel 統合**:コールバック、バリデーション、Dirty トラッキング、翻訳(I18n)を標準でサポートしています。
|
|
36
|
+
* **🚀 Rails ジェネレーター**:組み込みの Rails ジェネレーター CLI を使用して、エンティティクラスを瞬時に生成できます。
|
|
37
|
+
* **📦 シリアライズ**:`activemodel_object_info` を組み込みでサポートし、エンティティを Hash や JSON に簡単にシリアライズできます。
|
|
38
|
+
|
|
39
|
+
## 📦 インストール
|
|
40
|
+
|
|
41
|
+
アプリケーションの `Gemfile` に以下の行を追加します:
|
|
42
|
+
|
|
43
|
+
```ruby
|
|
44
|
+
gem 'sparrow-entity', require: 'sparrow'
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
その後、以下のコマンドを実行します:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
$ bundle install
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
または、以下のようにグローバルにインストールすることもできます:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
$ gem install sparrow-entity
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## 💻 使い方ガイド
|
|
60
|
+
|
|
61
|
+
### 1. 基本的なエンティティの定義
|
|
62
|
+
|
|
63
|
+
独自のエンティティを作成するには、単に `Sparrow::Base` を継承します。想定される Ruby の型とともにフィールドを定義できます。
|
|
64
|
+
|
|
65
|
+
```ruby
|
|
66
|
+
require 'sparrow' # Rails プロジェクトでは省略可能
|
|
67
|
+
|
|
68
|
+
#
|
|
69
|
+
# 外部の User サービスから取得したユーザーエンティティを表す
|
|
70
|
+
#
|
|
71
|
+
# [Changelog]
|
|
72
|
+
# - 1.0.0: Initial release
|
|
73
|
+
#
|
|
74
|
+
class UserEntity < Sparrow::Base
|
|
75
|
+
field :id, Integer
|
|
76
|
+
field :family_name, String
|
|
77
|
+
field :given_name, String
|
|
78
|
+
field :birthday, Date
|
|
79
|
+
field :nationality, String
|
|
80
|
+
|
|
81
|
+
#
|
|
82
|
+
# ユーザーのフルネームをフォーマットして返す
|
|
83
|
+
#
|
|
84
|
+
# @since 1.0.0
|
|
85
|
+
# @param [Hash] options フォーマットのオプション
|
|
86
|
+
# @option options [Symbol] :last 姓を最後に配置するかどうか
|
|
87
|
+
# @option options [String] :separator 姓名を結合する文字列
|
|
88
|
+
# @return [String] フォーマットされたフルネーム
|
|
89
|
+
#
|
|
90
|
+
def full_name(options = {})
|
|
91
|
+
last = options[:last] || :given
|
|
92
|
+
separator = options[:separator] || ' '
|
|
93
|
+
|
|
94
|
+
val = [family_name, given_name]
|
|
95
|
+
val.reverse! if last == :family
|
|
96
|
+
val.join(separator)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
user = UserEntity.new(id: 1, family_name: 'Doe', given_name: 'John')
|
|
101
|
+
puts user.full_name(last: :family) # => "John Doe"
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 2. 自動型変換
|
|
105
|
+
|
|
106
|
+
Sparrow は、代入された値を定義された型に自動的に変換しようと試みます。
|
|
107
|
+
|
|
108
|
+
```ruby
|
|
109
|
+
user = UserEntity.new
|
|
110
|
+
user.id = "42" # 文字列として代入
|
|
111
|
+
user.birthday = "2023-10-01" # 文字列として代入
|
|
112
|
+
|
|
113
|
+
puts user.id.class # => Integer (42)
|
|
114
|
+
puts user.birthday.class # => Date (<Date: 2023-10-01 ...>)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### 3. 真偽値(Boolean)フィールド
|
|
118
|
+
|
|
119
|
+
真偽値のロジックを扱うために、Sparrow は `Sparrow::Boolean` を提供しています。これは `.present?` のチェックや明示的な真偽値の等価性に基づいて、truthy な値と falsey な値を適切に処理します。
|
|
120
|
+
|
|
121
|
+
```ruby
|
|
122
|
+
class SettingsEntity < Sparrow::Base
|
|
123
|
+
field :notifications_enabled, Sparrow::Boolean
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
settings = SettingsEntity.new
|
|
127
|
+
puts settings.notifications_enabled.inspect # => nil
|
|
128
|
+
|
|
129
|
+
settings.notifications_enabled = 'yes'
|
|
130
|
+
puts settings.notifications_enabled # => true
|
|
131
|
+
|
|
132
|
+
settings.notifications_enabled = ''
|
|
133
|
+
puts settings.notifications_enabled # => false
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### 4. デフォルト値
|
|
137
|
+
|
|
138
|
+
`default:` オプションを提供することができます。代入された値が空または無効な場合、このデフォルト値にフォールバックします。
|
|
139
|
+
|
|
140
|
+
```ruby
|
|
141
|
+
class TaskEntity < Sparrow::Base
|
|
142
|
+
field :status, String, default: 'pending'
|
|
143
|
+
field :retry_count, Integer, default: 0
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
task = TaskEntity.new
|
|
147
|
+
puts task.status # => "pending"
|
|
148
|
+
puts task.retry_count # => 0
|
|
149
|
+
|
|
150
|
+
task.status = 'in_progress'
|
|
151
|
+
puts task.status # => "in_progress"
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### 5. ActiveModel の統合(バリデーションとコールバック)
|
|
155
|
+
|
|
156
|
+
Sparrow は `ActiveModel` モジュールをインクルードしているため、バリデーションやコールバック(`before_validation`、`after_initialize` など)をそのまま使用できます。
|
|
157
|
+
|
|
158
|
+
```ruby
|
|
159
|
+
class OrderEntity < Sparrow::Base
|
|
160
|
+
field :order_no, String
|
|
161
|
+
field :amount, Float
|
|
162
|
+
field :state, String, default: 'created'
|
|
163
|
+
|
|
164
|
+
validates :order_no, presence: true
|
|
165
|
+
validates :amount, numericality: { greater_than: 0 }
|
|
166
|
+
|
|
167
|
+
before_validation :generate_order_no, if: -> { order_no.blank? }
|
|
168
|
+
|
|
169
|
+
private
|
|
170
|
+
|
|
171
|
+
#
|
|
172
|
+
# 存在しない場合にランダムな注文番号を生成する
|
|
173
|
+
#
|
|
174
|
+
# @since 1.0.0
|
|
175
|
+
# @return [String] 生成された注文番号
|
|
176
|
+
#
|
|
177
|
+
def generate_order_no
|
|
178
|
+
self.order_no = "ORD-#{Time.now.to_i}"
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
order = OrderEntity.new(amount: 150.50)
|
|
183
|
+
order.valid? # => true
|
|
184
|
+
puts order.order_no # => "ORD-1698765432"
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### 6. シリアライズ
|
|
188
|
+
|
|
189
|
+
Sparrow は `activemodel_object_info`(v0.4.2+)を使用して、エンティティを Hash や JSON 形式に簡単にダンプできるようにサポートします。強力なコンテキスト設定、ホワイトリスト/ブラックリスト、カスタム Lambda フィルターなどの機能を提供します。
|
|
190
|
+
|
|
191
|
+
```ruby
|
|
192
|
+
class ProductEntity < Sparrow::Base
|
|
193
|
+
field :sku, String
|
|
194
|
+
field :price, Float
|
|
195
|
+
field :stock, Integer, default: 0
|
|
196
|
+
|
|
197
|
+
# デフォルトの出力設定を定義
|
|
198
|
+
INSTANCE_INFO = {
|
|
199
|
+
only: [:sku, :price],
|
|
200
|
+
attributes: [
|
|
201
|
+
:sku,
|
|
202
|
+
{ name: :price, type: :abstract, filter: ->(v) { "$#{format('%.2f', v)}" } }
|
|
203
|
+
]
|
|
204
|
+
}.freeze
|
|
205
|
+
|
|
206
|
+
# コンテキスト固有の出力設定を定義
|
|
207
|
+
INSTANCE_INFO_DETAIL = {
|
|
208
|
+
only: [:sku, :price, :stock]
|
|
209
|
+
}.freeze
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
product = ProductEntity.new(sku: 'MAC-M2-001', price: 1299.9)
|
|
213
|
+
|
|
214
|
+
# 標準的な属性の Hash
|
|
215
|
+
puts product.attributes
|
|
216
|
+
# => { sku: "MAC-M2-001", price: 1299.9, stock: 0 }
|
|
217
|
+
|
|
218
|
+
# 1. デフォルトで INSTANCE_INFO 定数を使用
|
|
219
|
+
puts product.instance_info
|
|
220
|
+
# => { sku: "MAC-M2-001", price: "$1299.90" }
|
|
221
|
+
|
|
222
|
+
# 2. コンテキスト出力:`context` を渡すことで INSTANCE_INFO_DETAIL を自動的に使用
|
|
223
|
+
puts product.instance_info(context: :detail)
|
|
224
|
+
# => { sku: "MAC-M2-001", price: 1299.9, stock: 0 }
|
|
225
|
+
|
|
226
|
+
# 3. 実行時の上書き
|
|
227
|
+
puts product.instance_info(only: [:sku])
|
|
228
|
+
# => { sku: "MAC-M2-001" }
|
|
229
|
+
|
|
230
|
+
# 4. 特定のフィールドを除外 (except)
|
|
231
|
+
puts product.instance_info(context: :detail, except: [:price])
|
|
232
|
+
# => { sku: "MAC-M2-001", stock: 0 }
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## 🚀 Rails 統合とジェネレーター
|
|
236
|
+
|
|
237
|
+
Ruby on Rails を使用している場合、`sparrow-entity` ファイルは自動的にロードされます。
|
|
238
|
+
|
|
239
|
+
組み込みのジェネレーターを使用して、エンティティクラスの雛形をすばやく作成できます:
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
$ rails g sparrow:entity Post::Reply
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
これにより、`app/entities/post/reply.rb` が生成されます:
|
|
246
|
+
|
|
247
|
+
```ruby
|
|
248
|
+
module Post
|
|
249
|
+
class Reply < Sparrow::Base
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## 📝 ライセンス
|
|
255
|
+
|
|
256
|
+
この Gem は [MIT ライセンス](https://opensource.org/licenses/MIT) の条件の下でオープンソースとして利用可能です。
|
data/README.md
CHANGED
|
@@ -1,152 +1,256 @@
|
|
|
1
|
-
# Sparrow
|
|
1
|
+
# 🐦 Sparrow Entity
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[English](./README.md) | [简体中文](./README.zh-CN.md) | [日本語](./README.ja.md)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://rubygems.org/gems/sparrow-entity)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
## 📖 Table of Contents
|
|
9
|
+
- [🌟 Introduction](#-introduction)
|
|
10
|
+
- [✨ Features](#-features)
|
|
11
|
+
- [📦 Installation](#-installation)
|
|
12
|
+
- [💻 Usage Guide](#-usage-guide)
|
|
13
|
+
- [1. Basic Entity Definition](#1-basic-entity-definition)
|
|
14
|
+
- [2. Automatic Type Casting](#2-automatic-type-casting)
|
|
15
|
+
- [3. Boolean Fields](#3-boolean-fields)
|
|
16
|
+
- [4. Default Values](#4-default-values)
|
|
17
|
+
- [5. ActiveModel Integrations (Validations & Callbacks)](#5-activemodel-integrations-validations--callbacks)
|
|
18
|
+
- [6. Serialization](#6-serialization)
|
|
19
|
+
- [🚀 Rails Integration & Generator](#-rails-integration--generator)
|
|
20
|
+
- [📝 License](#-license)
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 🌟 Introduction
|
|
25
|
+
|
|
26
|
+
**Sparrow Entity** is a lightweight Ruby gem designed to provide ORM-like entity modeling for non-database-backed data.
|
|
27
|
+
|
|
28
|
+
In modern architectures, especially microservices, applications often consume vast amounts of data from external APIs, message queues, or gRPC services rather than local databases. In these scenarios, `ActiveRecord::Base` cannot be used since there is no underlying database table. **Sparrow** perfectly fills this gap by allowing you to define structured, strongly-typed Entity objects (Plain Old Ruby Objects on steroids) with all the familiar ActiveModel conveniences.
|
|
29
|
+
|
|
30
|
+
## ✨ Features
|
|
31
|
+
|
|
32
|
+
* **🛠 ORM-like Experience**: Define attributes and types just like you would in ActiveRecord.
|
|
33
|
+
* **🗂 Automatic Type Casting**: Automatically converts assigned values to defined types (e.g., `String`, `Integer`, `Date`, `Sparrow::Boolean`).
|
|
34
|
+
* **⚙️ Default Values**: Set default fallback values for attributes when initialization is blank or invalid.
|
|
35
|
+
* **🛤 ActiveModel Integration**: Supports callbacks, validations, dirty tracking, and translations out of the box.
|
|
36
|
+
* **🚀 Rails Generator**: Instantly generate entity classes using the built-in Rails generator CLI.
|
|
37
|
+
* **📦 Serialization**: Built-in support for `activemodel_object_info` to easily serialize entities into Hashes/JSON.
|
|
38
|
+
|
|
39
|
+
## 📦 Installation
|
|
40
|
+
|
|
41
|
+
Add this line to your application's `Gemfile`:
|
|
8
42
|
|
|
9
43
|
```ruby
|
|
10
44
|
gem 'sparrow-entity', require: 'sparrow'
|
|
11
45
|
```
|
|
12
46
|
|
|
13
|
-
|
|
47
|
+
Then execute:
|
|
14
48
|
|
|
15
|
-
|
|
49
|
+
```bash
|
|
50
|
+
$ bundle install
|
|
51
|
+
```
|
|
16
52
|
|
|
17
|
-
|
|
53
|
+
Or install it globally via:
|
|
18
54
|
|
|
19
|
-
|
|
55
|
+
```bash
|
|
56
|
+
$ gem install sparrow-entity
|
|
57
|
+
```
|
|
20
58
|
|
|
21
|
-
##
|
|
59
|
+
## 💻 Usage Guide
|
|
22
60
|
|
|
23
|
-
###
|
|
61
|
+
### 1. Basic Entity Definition
|
|
24
62
|
|
|
25
|
-
|
|
63
|
+
To create your own entity, simply inherit from `Sparrow::Base`. You can define fields with their expected Ruby types.
|
|
26
64
|
|
|
27
65
|
```ruby
|
|
28
|
-
#
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
#
|
|
32
|
-
|
|
33
|
-
|
|
66
|
+
require 'sparrow' # Not required in Rails
|
|
67
|
+
|
|
68
|
+
#
|
|
69
|
+
# Represents a User entity fetched from an external User Service
|
|
70
|
+
#
|
|
71
|
+
# [Changelog]
|
|
72
|
+
# - 1.0.0: Initial release
|
|
73
|
+
#
|
|
74
|
+
class UserEntity < Sparrow::Base
|
|
34
75
|
field :id, Integer
|
|
35
76
|
field :family_name, String
|
|
36
77
|
field :given_name, String
|
|
37
|
-
field :gender, Integer
|
|
38
78
|
field :birthday, Date
|
|
39
79
|
field :nationality, String
|
|
40
|
-
# 也可以给与属性默认值,如果属性值本身无效时获取该属性会返回默认值
|
|
41
|
-
field :status, String, default: 'good'
|
|
42
80
|
|
|
43
|
-
#
|
|
44
|
-
|
|
81
|
+
#
|
|
82
|
+
# Format and return the full name of the user
|
|
83
|
+
#
|
|
84
|
+
# @since 1.0.0
|
|
85
|
+
# @param [Hash] options formatting options
|
|
86
|
+
# @option options [Symbol] :last whether to place family name last or first
|
|
87
|
+
# @option options [String] :separator string used to join names
|
|
88
|
+
# @return [String] the formatted full name
|
|
89
|
+
#
|
|
90
|
+
def full_name(options = {})
|
|
91
|
+
last = options[:last] || :given
|
|
92
|
+
separator = options[:separator] || ' '
|
|
93
|
+
|
|
45
94
|
val = [family_name, given_name]
|
|
46
95
|
val.reverse! if last == :family
|
|
47
|
-
val.join(
|
|
96
|
+
val.join(separator)
|
|
48
97
|
end
|
|
49
98
|
end
|
|
99
|
+
|
|
100
|
+
user = UserEntity.new(id: 1, family_name: 'Doe', given_name: 'John')
|
|
101
|
+
puts user.full_name(last: :family) # => "John Doe"
|
|
50
102
|
```
|
|
51
103
|
|
|
52
|
-
|
|
104
|
+
### 2. Automatic Type Casting
|
|
105
|
+
|
|
106
|
+
Sparrow will attempt to coerce assigned values into the defined types automatically.
|
|
53
107
|
|
|
54
108
|
```ruby
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
#
|
|
109
|
+
user = UserEntity.new
|
|
110
|
+
user.id = "42" # Assigned as a String
|
|
111
|
+
user.birthday = "2023-10-01" # Assigned as a String
|
|
112
|
+
|
|
113
|
+
puts user.id.class # => Integer (42)
|
|
114
|
+
puts user.birthday.class # => Date (<Date: 2023-10-01 ...>)
|
|
58
115
|
```
|
|
59
116
|
|
|
60
|
-
###
|
|
117
|
+
### 3. Boolean Fields
|
|
61
118
|
|
|
62
|
-
|
|
119
|
+
For boolean logic, Sparrow provides `Sparrow::Boolean`. It handles truthy and falsey values gracefully based on `.present?` checks or explicit boolean equivalents.
|
|
63
120
|
|
|
64
121
|
```ruby
|
|
65
|
-
class
|
|
66
|
-
field :
|
|
122
|
+
class SettingsEntity < Sparrow::Base
|
|
123
|
+
field :notifications_enabled, Sparrow::Boolean
|
|
67
124
|
end
|
|
68
125
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
# => nil
|
|
72
|
-
|
|
73
|
-
obj.married = true
|
|
74
|
-
obj.married
|
|
75
|
-
# => true
|
|
126
|
+
settings = SettingsEntity.new
|
|
127
|
+
puts settings.notifications_enabled.inspect # => nil
|
|
76
128
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
# => false
|
|
129
|
+
settings.notifications_enabled = 'yes'
|
|
130
|
+
puts settings.notifications_enabled # => true
|
|
80
131
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
# => true
|
|
132
|
+
settings.notifications_enabled = ''
|
|
133
|
+
puts settings.notifications_enabled # => false
|
|
84
134
|
```
|
|
85
135
|
|
|
86
|
-
###
|
|
136
|
+
### 4. Default Values
|
|
87
137
|
|
|
88
|
-
|
|
138
|
+
You can provide a `default:` option. If the assigned value is empty or invalid, it will fallback to this default value.
|
|
89
139
|
|
|
90
140
|
```ruby
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
141
|
+
class TaskEntity < Sparrow::Base
|
|
142
|
+
field :status, String, default: 'pending'
|
|
143
|
+
field :retry_count, Integer, default: 0
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
task = TaskEntity.new
|
|
147
|
+
puts task.status # => "pending"
|
|
148
|
+
puts task.retry_count # => 0
|
|
149
|
+
|
|
150
|
+
task.status = 'in_progress'
|
|
151
|
+
puts task.status # => "in_progress"
|
|
95
152
|
```
|
|
96
153
|
|
|
97
|
-
###
|
|
154
|
+
### 5. ActiveModel Integrations (Validations & Callbacks)
|
|
98
155
|
|
|
99
|
-
|
|
156
|
+
Because Sparrow includes `ActiveModel` modules, you can use validations and callbacks (`before_validation`, `after_initialize`, etc.) out of the box.
|
|
100
157
|
|
|
101
158
|
```ruby
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
159
|
+
class OrderEntity < Sparrow::Base
|
|
160
|
+
field :order_no, String
|
|
161
|
+
field :amount, Float
|
|
162
|
+
field :state, String, default: 'created'
|
|
163
|
+
|
|
164
|
+
validates :order_no, presence: true
|
|
165
|
+
validates :amount, numericality: { greater_than: 0 }
|
|
166
|
+
|
|
167
|
+
before_validation :generate_order_no, if: -> { order_no.blank? }
|
|
168
|
+
|
|
169
|
+
private
|
|
170
|
+
|
|
171
|
+
#
|
|
172
|
+
# Generate a random order number if not present
|
|
173
|
+
#
|
|
174
|
+
# @since 1.0.0
|
|
175
|
+
# @return [String] the generated order number
|
|
176
|
+
#
|
|
177
|
+
def generate_order_no
|
|
178
|
+
self.order_no = "ORD-#{Time.now.to_i}"
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
order = OrderEntity.new(amount: 150.50)
|
|
183
|
+
order.valid? # => true
|
|
184
|
+
puts order.order_no # => "ORD-1698765432"
|
|
107
185
|
```
|
|
108
186
|
|
|
109
|
-
###
|
|
187
|
+
### 6. Serialization
|
|
110
188
|
|
|
111
|
-
|
|
189
|
+
Sparrow leverages `activemodel_object_info` (v0.4.2+) to easily dump entities into Hashes or JSON formats, offering powerful contextual formatting, whitelisting/blacklisting, and custom lambdas.
|
|
112
190
|
|
|
113
|
-
|
|
191
|
+
```ruby
|
|
192
|
+
class ProductEntity < Sparrow::Base
|
|
193
|
+
field :sku, String
|
|
194
|
+
field :price, Float
|
|
195
|
+
field :stock, Integer, default: 0
|
|
196
|
+
|
|
197
|
+
# Define default output configuration
|
|
198
|
+
INSTANCE_INFO = {
|
|
199
|
+
only: [:sku, :price],
|
|
200
|
+
attributes: [
|
|
201
|
+
:sku,
|
|
202
|
+
{ name: :price, type: :abstract, filter: ->(v) { "$#{format('%.2f', v)}" } }
|
|
203
|
+
]
|
|
204
|
+
}.freeze
|
|
205
|
+
|
|
206
|
+
# Define contextual output configuration
|
|
207
|
+
INSTANCE_INFO_DETAIL = {
|
|
208
|
+
only: [:sku, :price, :stock]
|
|
209
|
+
}.freeze
|
|
210
|
+
end
|
|
114
211
|
|
|
115
|
-
|
|
212
|
+
product = ProductEntity.new(sku: 'MAC-M2-001', price: 1299.9)
|
|
116
213
|
|
|
117
|
-
|
|
214
|
+
# Standard attributes hash
|
|
215
|
+
puts product.attributes
|
|
216
|
+
# => { sku: "MAC-M2-001", price: 1299.9, stock: 0 }
|
|
118
217
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
218
|
+
# 1. Uses default INSTANCE_INFO constant
|
|
219
|
+
puts product.instance_info
|
|
220
|
+
# => { sku: "MAC-M2-001", price: "$1299.90" }
|
|
221
|
+
|
|
222
|
+
# 2. Contextual output: Pass `context` to use INSTANCE_INFO_DETAIL
|
|
223
|
+
puts product.instance_info(context: :detail)
|
|
224
|
+
# => { sku: "MAC-M2-001", price: 1299.9, stock: 0 }
|
|
225
|
+
|
|
226
|
+
# 3. Override at runtime
|
|
227
|
+
puts product.instance_info(only: [:sku])
|
|
228
|
+
# => { sku: "MAC-M2-001" }
|
|
229
|
+
|
|
230
|
+
# 4. Exclude specific fields (except)
|
|
231
|
+
puts product.instance_info(context: :detail, except: [:price])
|
|
232
|
+
# => { sku: "MAC-M2-001", stock: 0 }
|
|
124
233
|
```
|
|
125
234
|
|
|
126
|
-
|
|
235
|
+
## 🚀 Rails Integration & Generator
|
|
127
236
|
|
|
128
|
-
|
|
237
|
+
If you are using Ruby on Rails, `sparrow-entity` files will be automatically required.
|
|
129
238
|
|
|
130
|
-
|
|
239
|
+
You can use the built-in generator to quickly scaffold entity classes:
|
|
131
240
|
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
attributes: [
|
|
135
|
-
{ name: :full_name, type: :method },
|
|
136
|
-
{ name: :sex, as: :gender, type: :abstract, filter: ->(v) { v == 1 ? 'Male' : 'Female' } },
|
|
137
|
-
],
|
|
138
|
-
}.freeze
|
|
139
|
-
|
|
140
|
-
me.instance_info(OUTPUT)
|
|
141
|
-
# => { full_name: "张三", sex: "Male" }
|
|
241
|
+
```bash
|
|
242
|
+
$ rails g sparrow:entity Post::Reply
|
|
142
243
|
```
|
|
143
244
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
内置 Rake 命令包括了控制台开启命令 `rake c` 或者 `rake console` 即可开启控制台模式。
|
|
245
|
+
This will generate `app/entities/post/reply.rb`:
|
|
147
246
|
|
|
148
|
-
|
|
247
|
+
```ruby
|
|
248
|
+
module Post
|
|
249
|
+
class Reply < Sparrow::Base
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
```
|
|
149
253
|
|
|
150
|
-
## License
|
|
254
|
+
## 📝 License
|
|
151
255
|
|
|
152
256
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/README.zh-CN.md
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
# 🐦 Sparrow Entity
|
|
2
|
+
|
|
3
|
+
[English](./README.md) | [简体中文](./README.zh-CN.md) | [日本語](./README.ja.md)
|
|
4
|
+
|
|
5
|
+
[](https://rubygems.org/gems/sparrow-entity)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
## 📖 目录
|
|
9
|
+
- [🌟 简介](#-简介)
|
|
10
|
+
- [✨ 特性](#-特性)
|
|
11
|
+
- [📦 安装](#-安装)
|
|
12
|
+
- [💻 使用指南](#-使用指南)
|
|
13
|
+
- [1. 基础实体定义](#1-基础实体定义)
|
|
14
|
+
- [2. 自动类型转换](#2-自动类型转换)
|
|
15
|
+
- [3. 布尔类型字段](#3-布尔类型字段)
|
|
16
|
+
- [4. 默认值](#4-默认值)
|
|
17
|
+
- [5. ActiveModel 集成(验证与回调)](#5-activemodel-集成验证与回调)
|
|
18
|
+
- [6. 序列化能力](#6-序列化能力)
|
|
19
|
+
- [🚀 Rails 集成与生成器](#-rails-集成与生成器)
|
|
20
|
+
- [📝 许可协议](#-许可协议)
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 🌟 简介
|
|
25
|
+
|
|
26
|
+
**Sparrow Entity** 是一个轻量级的 Ruby Gem,旨在为非数据库支持的数据提供类似 ORM 的实体建模能力。
|
|
27
|
+
|
|
28
|
+
在现代系统架构(尤其是微服务架构)中,应用程序往往需要从外部 API、消息队列或 gRPC 服务中获取并处理大量数据,而不是直接读取本地数据库。在这些场景下,由于没有底层数据库表,我们无法使用 `ActiveRecord::Base`。**Sparrow** 完美地填补了这一空白,允许您定义结构化、强类型的实体对象(强化版的普通 Ruby 对象),并保留所有大家熟悉的 ActiveModel 优势。
|
|
29
|
+
|
|
30
|
+
## ✨ 特性
|
|
31
|
+
|
|
32
|
+
* **🛠 类似 ORM 的体验**:像在 ActiveRecord 中一样定义属性和类型。
|
|
33
|
+
* **🗂 自动类型转换**:自动将赋的值转换为预期的类型(例如 `String`、`Integer`、`Date`、`Sparrow::Boolean` 等)。
|
|
34
|
+
* **⚙️ 默认值**:当初始化值为空或无效时,支持为属性设置默认回退值。
|
|
35
|
+
* **🛤 ActiveModel 集成**:开箱即用地支持回调(Callbacks)、验证(Validations)、脏数据追踪(Dirty Tracking)和国际化(I18n)。
|
|
36
|
+
* **🚀 Rails 生成器**:使用内置的 Rails 生成器 CLI 可以一键生成实体类。
|
|
37
|
+
* **📦 序列化能力**:内置支持 `activemodel_object_info`,可轻松将实体序列化为 Hash/JSON。
|
|
38
|
+
|
|
39
|
+
## 📦 安装
|
|
40
|
+
|
|
41
|
+
在您应用的 `Gemfile` 中添加以下代码:
|
|
42
|
+
|
|
43
|
+
```ruby
|
|
44
|
+
gem 'sparrow-entity', require: 'sparrow'
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
然后执行安装:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
$ bundle install
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
或者使用全局安装命令:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
$ gem install sparrow-entity
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## 💻 使用指南
|
|
60
|
+
|
|
61
|
+
### 1. 基础实体定义
|
|
62
|
+
|
|
63
|
+
要创建您自己的实体,只需继承 `Sparrow::Base`。您可以定义字段并指定预期的 Ruby 类型。
|
|
64
|
+
|
|
65
|
+
```ruby
|
|
66
|
+
require 'sparrow' # 在 Rails 项目中可省略
|
|
67
|
+
|
|
68
|
+
#
|
|
69
|
+
# 表示从外部用户服务获取的用户实体
|
|
70
|
+
#
|
|
71
|
+
# [Changelog]
|
|
72
|
+
# - 1.0.0: Initial release
|
|
73
|
+
#
|
|
74
|
+
class UserEntity < Sparrow::Base
|
|
75
|
+
field :id, Integer
|
|
76
|
+
field :family_name, String
|
|
77
|
+
field :given_name, String
|
|
78
|
+
field :birthday, Date
|
|
79
|
+
field :nationality, String
|
|
80
|
+
|
|
81
|
+
#
|
|
82
|
+
# 格式化并返回用户的全名
|
|
83
|
+
#
|
|
84
|
+
# @since 1.0.0
|
|
85
|
+
# @param [Hash] options 格式化选项
|
|
86
|
+
# @option options [Symbol] :last 是否将姓氏放在最后
|
|
87
|
+
# @option options [String] :separator 用于连接姓和名的字符串
|
|
88
|
+
# @return [String] 格式化后的全名
|
|
89
|
+
#
|
|
90
|
+
def full_name(options = {})
|
|
91
|
+
last = options[:last] || :given
|
|
92
|
+
separator = options[:separator] || ' '
|
|
93
|
+
|
|
94
|
+
val = [family_name, given_name]
|
|
95
|
+
val.reverse! if last == :family
|
|
96
|
+
val.join(separator)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
user = UserEntity.new(id: 1, family_name: 'Doe', given_name: 'John')
|
|
101
|
+
puts user.full_name(last: :family) # => "John Doe"
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 2. 自动类型转换
|
|
105
|
+
|
|
106
|
+
Sparrow 会尝试自动将赋值转换为定义好的类型。
|
|
107
|
+
|
|
108
|
+
```ruby
|
|
109
|
+
user = UserEntity.new
|
|
110
|
+
user.id = "42" # 以字符串形式赋值
|
|
111
|
+
user.birthday = "2023-10-01" # 以字符串形式赋值
|
|
112
|
+
|
|
113
|
+
puts user.id.class # => Integer (42)
|
|
114
|
+
puts user.birthday.class # => Date (<Date: 2023-10-01 ...>)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### 3. 布尔类型字段
|
|
118
|
+
|
|
119
|
+
针对布尔逻辑,Sparrow 提供了 `Sparrow::Boolean` 类型。它可以根据 `.present?` 检查或明确的布尔等效值,优雅地处理真值和假值。
|
|
120
|
+
|
|
121
|
+
```ruby
|
|
122
|
+
class SettingsEntity < Sparrow::Base
|
|
123
|
+
field :notifications_enabled, Sparrow::Boolean
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
settings = SettingsEntity.new
|
|
127
|
+
puts settings.notifications_enabled.inspect # => nil
|
|
128
|
+
|
|
129
|
+
settings.notifications_enabled = 'yes'
|
|
130
|
+
puts settings.notifications_enabled # => true
|
|
131
|
+
|
|
132
|
+
settings.notifications_enabled = ''
|
|
133
|
+
puts settings.notifications_enabled # => false
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### 4. 默认值
|
|
137
|
+
|
|
138
|
+
您可以提供一个 `default:` 选项。如果赋的值为空或无效,则将退回到此默认值。
|
|
139
|
+
|
|
140
|
+
```ruby
|
|
141
|
+
class TaskEntity < Sparrow::Base
|
|
142
|
+
field :status, String, default: 'pending'
|
|
143
|
+
field :retry_count, Integer, default: 0
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
task = TaskEntity.new
|
|
147
|
+
puts task.status # => "pending"
|
|
148
|
+
puts task.retry_count # => 0
|
|
149
|
+
|
|
150
|
+
task.status = 'in_progress'
|
|
151
|
+
puts task.status # => "in_progress"
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### 5. ActiveModel 集成(验证与回调)
|
|
155
|
+
|
|
156
|
+
由于 Sparrow 引入了 `ActiveModel` 的相关模块,您可以直接使用验证和回调(如 `before_validation`, `after_initialize` 等)。
|
|
157
|
+
|
|
158
|
+
```ruby
|
|
159
|
+
class OrderEntity < Sparrow::Base
|
|
160
|
+
field :order_no, String
|
|
161
|
+
field :amount, Float
|
|
162
|
+
field :state, String, default: 'created'
|
|
163
|
+
|
|
164
|
+
validates :order_no, presence: true
|
|
165
|
+
validates :amount, numericality: { greater_than: 0 }
|
|
166
|
+
|
|
167
|
+
before_validation :generate_order_no, if: -> { order_no.blank? }
|
|
168
|
+
|
|
169
|
+
private
|
|
170
|
+
|
|
171
|
+
#
|
|
172
|
+
# 如果不存在则生成随机的订单号
|
|
173
|
+
#
|
|
174
|
+
# @since 1.0.0
|
|
175
|
+
# @return [String] 生成的订单号
|
|
176
|
+
#
|
|
177
|
+
def generate_order_no
|
|
178
|
+
self.order_no = "ORD-#{Time.now.to_i}"
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
order = OrderEntity.new(amount: 150.50)
|
|
183
|
+
order.valid? # => true
|
|
184
|
+
puts order.order_no # => "ORD-1698765432"
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### 6. 序列化能力
|
|
188
|
+
|
|
189
|
+
Sparrow 利用 `activemodel_object_info`(v0.4.2+)帮助您轻松地将实体对象转储为 Hash 或 JSON 格式,并提供强大的上下文配置、白名单/黑名单以及自定义 Lambda 过滤等功能。
|
|
190
|
+
|
|
191
|
+
```ruby
|
|
192
|
+
class ProductEntity < Sparrow::Base
|
|
193
|
+
field :sku, String
|
|
194
|
+
field :price, Float
|
|
195
|
+
field :stock, Integer, default: 0
|
|
196
|
+
|
|
197
|
+
# 定义默认输出配置
|
|
198
|
+
INSTANCE_INFO = {
|
|
199
|
+
only: [:sku, :price],
|
|
200
|
+
attributes: [
|
|
201
|
+
:sku,
|
|
202
|
+
{ name: :price, type: :abstract, filter: ->(v) { "$#{format('%.2f', v)}" } }
|
|
203
|
+
]
|
|
204
|
+
}.freeze
|
|
205
|
+
|
|
206
|
+
# 定义特定上下文输出配置
|
|
207
|
+
INSTANCE_INFO_DETAIL = {
|
|
208
|
+
only: [:sku, :price, :stock]
|
|
209
|
+
}.freeze
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
product = ProductEntity.new(sku: 'MAC-M2-001', price: 1299.9)
|
|
213
|
+
|
|
214
|
+
# 标准的属性 Hash
|
|
215
|
+
puts product.attributes
|
|
216
|
+
# => { sku: "MAC-M2-001", price: 1299.9, stock: 0 }
|
|
217
|
+
|
|
218
|
+
# 1. 默认使用 INSTANCE_INFO 常量
|
|
219
|
+
puts product.instance_info
|
|
220
|
+
# => { sku: "MAC-M2-001", price: "$1299.90" }
|
|
221
|
+
|
|
222
|
+
# 2. 上下文输出:通过传入 `context` 自动使用 INSTANCE_INFO_DETAIL
|
|
223
|
+
puts product.instance_info(context: :detail)
|
|
224
|
+
# => { sku: "MAC-M2-001", price: 1299.9, stock: 0 }
|
|
225
|
+
|
|
226
|
+
# 3. 运行时覆盖
|
|
227
|
+
puts product.instance_info(only: [:sku])
|
|
228
|
+
# => { sku: "MAC-M2-001" }
|
|
229
|
+
|
|
230
|
+
# 4. 排除特定字段 (except)
|
|
231
|
+
puts product.instance_info(context: :detail, except: [:price])
|
|
232
|
+
# => { sku: "MAC-M2-001", stock: 0 }
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## 🚀 Rails 集成与生成器
|
|
236
|
+
|
|
237
|
+
如果您正在使用 Ruby on Rails 框架,`sparrow-entity` 会被自动加载。
|
|
238
|
+
|
|
239
|
+
您可以使用内置生成器快速搭建实体类的基础代码:
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
$ rails g sparrow:entity Post::Reply
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
这将在 `app/entities/post/reply.rb` 中生成以下代码:
|
|
246
|
+
|
|
247
|
+
```ruby
|
|
248
|
+
module Post
|
|
249
|
+
class Reply < Sparrow::Base
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## 📝 许可协议
|
|
255
|
+
|
|
256
|
+
此 Gem 遵循 [MIT 许可协议](https://opensource.org/licenses/MIT) 作为开源软件发布。
|
data/lib/sparrow/version.rb
CHANGED
data/sparrow.gemspec
CHANGED
|
@@ -14,6 +14,7 @@ Gem::Specification.new do |spec|
|
|
|
14
14
|
spec.description = Sparrow::DESCRIPTION
|
|
15
15
|
spec.homepage = 'https://github.com/shiner527/sparrow'
|
|
16
16
|
spec.license = 'MIT'
|
|
17
|
+
spec.required_ruby_version = '>= 2.7.7'
|
|
17
18
|
|
|
18
19
|
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
|
19
20
|
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
|
@@ -39,7 +40,7 @@ Gem::Specification.new do |spec|
|
|
|
39
40
|
spec.require_paths = ['lib']
|
|
40
41
|
|
|
41
42
|
spec.add_dependency 'activemodel'
|
|
42
|
-
spec.add_dependency 'activemodel_object_info', '>= 0.
|
|
43
|
+
spec.add_dependency 'activemodel_object_info', '>= 0.4.2'
|
|
43
44
|
spec.add_dependency 'activesupport'
|
|
44
45
|
|
|
45
46
|
spec.add_development_dependency 'bundler'
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sparrow-entity
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- shiner
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-07-30 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activemodel
|
|
@@ -30,14 +30,14 @@ dependencies:
|
|
|
30
30
|
requirements:
|
|
31
31
|
- - ">="
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: 0.
|
|
33
|
+
version: 0.4.2
|
|
34
34
|
type: :runtime
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
38
|
- - ">="
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: 0.
|
|
40
|
+
version: 0.4.2
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: activesupport
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -170,7 +170,9 @@ files:
|
|
|
170
170
|
- Gemfile
|
|
171
171
|
- Gemfile.lock
|
|
172
172
|
- LICENSE
|
|
173
|
+
- README.ja.md
|
|
173
174
|
- README.md
|
|
175
|
+
- README.zh-CN.md
|
|
174
176
|
- Rakefile
|
|
175
177
|
- bin/console
|
|
176
178
|
- bin/setup
|
|
@@ -202,7 +204,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
202
204
|
requirements:
|
|
203
205
|
- - ">="
|
|
204
206
|
- !ruby/object:Gem::Version
|
|
205
|
-
version:
|
|
207
|
+
version: 2.7.7
|
|
206
208
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
207
209
|
requirements:
|
|
208
210
|
- - ">="
|