export_to 1.2.1 → 1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d42bfa7144883c0c4771feeb77e75b8555d957c573a319cc770238f8a28bdc62
4
- data.tar.gz: eb76e5d51d0b5ee9e2c88bd6e2badffa4b383aef5ca1817765594d9d997a5538
3
+ metadata.gz: 48ade8d2d2cc83728bcbbebf003187ac72d515f42e65645e67a91ba4021936ce
4
+ data.tar.gz: ea3754d3619c1d7fcf73c26c7eb2205f6de0caf43e9fd9731b155a4feda6f595
5
5
  SHA512:
6
- metadata.gz: fb193c89469a61cc10f62535edaca799f5cc4a5de0a4a8f78f3412488aa2b01f423b5743cf366bc25c076ea68150bd51396d892f7ab5667451e5b5016ac5189f
7
- data.tar.gz: d5405dc6670c5961ed6af6bd3f2352e5bd4c01e8dd180c56d79d96800971b2a8f7f9eda1484b9cc43cc6a896379417de561207f4ff83a7a1a11a7385bd6744ea
6
+ metadata.gz: 0a63b654da5d5bcf77bb87853e3c0f8c3cd7b0d985a40204e6ef259ad12da528e96f8077523464a5d7ba202a450b08c8f483431d0ffe022901e0421399de1e72
7
+ data.tar.gz: f311a3013ffac1fd95eca922865e9df4c427db2a9dd7c0dca8f8c3bf2188b2716aca16dc869d2d9909a5a2d6afaa237edfd429912aef1accbd62b6329e93f586
data/CHANGELOG.md ADDED
@@ -0,0 +1,113 @@
1
+ # 更新紀錄(Changelog)
2
+
3
+ 本檔記錄此專案所有值得注意的變更。
4
+
5
+ 格式參考 [Keep a Changelog](https://keepachangelog.com/zh-TW/1.1.0/),版本號遵循 [Semantic Versioning](https://semver.org/lang/zh-TW/)。
6
+
7
+ ## [Unreleased]
8
+
9
+ ### Added
10
+
11
+ - 新增 `CHANGELOG.md`。
12
+ - 完整的 `README.md`:概述、環境需求、安裝、DSL 用法、開發與發版流程。
13
+ - CLAUDE.md 規則:每個 PR 都必須同步更新 `README.md` 與 `CHANGELOG.md`;`README.md` 與 `CHANGELOG.md` 一律用繁體中文撰寫。
14
+
15
+ ### Changed
16
+
17
+ - `README.md`、`CHANGELOG.md` 改以繁體中文(zh-TW)撰寫。
18
+
19
+ ## [1.3.0] - 2026-10-27
20
+
21
+ ### Fixed
22
+
23
+ - `ExportTo::Base#each` 每次呼叫都會 raise `NoMethodError (undefined method 'rows!')`。現在會回傳所有列組成的 Array(第一列是標題列,內容與 `#to_csv` 相同);帶 block 時會逐列 yield 並回傳 exporter 本身,因此 Enumerable 方法(`map`、`to_a` 等)也能使用。`#each!` 沒有變動。
24
+ - `TESTING.md` 與 `bin/test_all` 已過時(只涵蓋 Ruby 2.7–3.1)。現在它們的說明與執行內容都與 `.github/workflows/ci.yml` 的矩陣一致。
25
+
26
+ ### Deprecated
27
+
28
+ - `ExportTo::Base#to_xls`:自 1.0.0 起它回傳的就是 **XLSX** 資料(與 `#to_xlsx` 相同),而不是舊版 `.xls` 檔。為了不讓既有呼叫端壞掉,回傳值維持不變,但現在會印出一次性的 `[DEPRECATION]` 警告(輸出到 `$stderr`,每個 process 一次)。請改用 `#to_xlsx`;若要真正的 `.xls`,請用 `ExportTo::Exporter::Xls.new(export).to_xls`。未來的 major 版本可能會讓 `#to_xls` 回傳真正的 `.xls` 檔,或將它移除。
29
+
30
+ ### Added
31
+
32
+ - 測試:`#each`、`#to_xls` 的相容性(仍回傳 XLSX)與其棄用警告、`#to_xlsx` / `ExportTo::Exporter::Xls` 的輸出格式。
33
+
34
+ ## [1.2.1] - 2026-10-27
35
+
36
+ ### Added
37
+
38
+ - 支援 Rails 8.0 / 8.1 與 Ruby 3.4(`activesupport` 現在放寬到 `< 8.2`;`csv` gem 改為明確相依;移除 `required_ruby_version` 的上限;新增 `ruby_3.3_rails_8.*` / `ruby_3.4_rails_8.*` gemfile 與對應的 CI job)。
39
+ - GitHub Actions `publish.yml`:新版本進到 `master` 時,透過 Trusted Publishing 自動發佈到 RubyGems。
40
+ - CLAUDE.md 加入發版規則。
41
+
42
+ ### Changed
43
+
44
+ - 移除每個 gemfile 各自的舊 lockfile,這些 lockfile 會讓 CI 在較舊的 Ruby 上失敗。
45
+
46
+ ## [1.2.0] - 2026-01-08
47
+
48
+ ### Added
49
+
50
+ - 新增 Ruby 3.2 與 3.3 的測試 gemfile(`ruby_3.2_rails_7.0`、`ruby_3.2_rails_7.1`、`ruby_3.3_rails_7.1`)與 CI job。
51
+
52
+ ### Changed
53
+
54
+ - gemspec 的 `required_ruby_version` 上限由 `< 3.2.0` 提高到 `< 3.4.0`。
55
+
56
+ ## [1.1.2] - 2026-01-07
57
+
58
+ ### Changed
59
+
60
+ - 更新各 gemfile 的 lockfile。
61
+
62
+ ## [1.1.1] - 2026-01-07
63
+
64
+ ### Added
65
+
66
+ - 多版本 Ruby / Rails 測試環境:每個版本各自的 gemfile、GitHub Actions 矩陣、`bin/test_all`、`bin/check_dependencies` 與 `TESTING.md`。
67
+
68
+ ### Fixed
69
+
70
+ - 測試不再依賴寫死的 macOS 路徑。
71
+
72
+ ## [1.1.0] - 2023-02-02
73
+
74
+ ### Changed
75
+
76
+ - 修正並微調 XLSX exporter(`ExportTo::Exporter::Xlsx`)。
77
+
78
+ ## [1.0.0] - 2023-02-02
79
+
80
+ ### Changed
81
+
82
+ - 內部改寫:匯出邏輯移到 `ExportTo::Exporter::Csv` / `Xls` / `Xlsx`;`ExportTo::Base` 提供 `to_csv`、`to_xlsx` 與 `to_xls`。
83
+ - `activesupport` 限制為 `>= 6, < 7`;開發相依套件放寬為 `bundler >= 2.0`、`rake >= 13`。
84
+
85
+ ## [0.1.2] - 2019-06-19
86
+
87
+ ### Changed
88
+
89
+ - CSV 輸出現在會強制幫每個欄位加上引號。
90
+
91
+ ## [0.1.1] - 2018-12-05
92
+
93
+ ### Fixed
94
+
95
+ - 修正匯出時出現 "File exists" 的 bug。
96
+
97
+ ## [0.1.0] - 2018-10-21
98
+
99
+ ### Added
100
+
101
+ - 首次發佈:`ExportTo::Base` DSL(`set`、`joins`、`presenter`、`each_with`)、帶有列計數器的 presenter、空的 join relation 處理,以及 `to_xlsx`。
102
+
103
+ [Unreleased]: https://github.com/superlanding/export_to/compare/v1.3.0...HEAD
104
+ [1.3.0]: https://github.com/superlanding/export_to/compare/v1.2.1...v1.3.0
105
+ [1.2.1]: https://github.com/superlanding/export_to/compare/v1.2.0...v1.2.1
106
+ [1.2.0]: https://github.com/superlanding/export_to/compare/v1.1.2...v1.2.0
107
+ [1.1.2]: https://github.com/superlanding/export_to/compare/v1.1.1...v1.1.2
108
+ [1.1.1]: https://github.com/superlanding/export_to/releases/tag/v1.1.1
109
+ [1.1.0]: https://github.com/superlanding/export_to/commit/48957da
110
+ [1.0.0]: https://github.com/superlanding/export_to/commit/8d7f937
111
+ [0.1.2]: https://github.com/superlanding/export_to/commit/d276482
112
+ [0.1.1]: https://github.com/superlanding/export_to/commit/12dd5c1
113
+ [0.1.0]: https://github.com/superlanding/export_to/commit/d605bf9
data/CLAUDE.md CHANGED
@@ -7,3 +7,15 @@
7
7
  - 跳版規則(Semantic Versioning):修 bug 跳 patch(x.y.Z);新增相容功能跳 minor(x.Y.0);不相容變更跳 major(X.0.0)。
8
8
  - 版號只改在 PR 裡。AI 帳號只能開 branch 與 PR,不得合併到 master;只有真人帳號可以合併。合併就等於批准發佈。
9
9
  - 不得為了讓測試通過而改變程式原本的行為。
10
+
11
+ ## 文件與更新紀錄(README / CHANGELOG)
12
+
13
+ - **每一個 PR 都必須同步更新文件**:
14
+ - 只要行為、用法、設定、相依套件或支援的 Ruby / Rails 版本有變,就要更新 `README.md`。
15
+ - 一律要在 `CHANGELOG.md` 新增一筆條目([Keep a Changelog](https://keepachangelog.com/zh-TW/1.1.0/) 格式,分類用 Added / Changed / Deprecated / Removed / Fixed / Security)。
16
+ - **語言規則**:`README.md` 與 `CHANGELOG.md` 一律用繁體中文(zh-TW,台灣用語)撰寫;程式碼、識別字(class / 方法 / 變數名稱)、指令、檔名與路徑維持英文,不要翻譯。
17
+ - `CHANGELOG.md` 的寫法:
18
+ - 沒有跳版號的 PR:寫在最上方的 `## [Unreleased]` 底下。
19
+ - 有跳版號的 PR:把條目寫在新的版本章節 `## [x.y.z] - YYYY-MM-DD`(日期為合併日),並同步更新檔尾的版本比較連結。
20
+ - 版本號必須與 rubygems.org 上實際發佈的版本一致,不得寫還沒發佈的版本。
21
+ - 只改文件、CI 或 CLAUDE.md 的 PR 不需要跳版號,但仍要在 `CHANGELOG.md` 的 `Unreleased` 補一筆。
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- export_to (1.2.1)
4
+ export_to (1.3.0)
5
5
  activesupport (>= 6.0, < 8.2)
6
6
  csv
7
7
  fast_excel (~> 0.4)
data/README.md CHANGED
@@ -1,64 +1,156 @@
1
1
  # ExportTo
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/export_to`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ [![Gem Version](https://badge.fury.io/rb/export_to.svg)](https://rubygems.org/gems/export_to)
4
+ [![CI](https://github.com/superlanding/export_to/actions/workflows/ci.yml/badge.svg)](https://github.com/superlanding/export_to/actions/workflows/ci.yml)
4
5
 
5
- TODO: Delete this and the text above, and describe your gem
6
+ 用一套簡單的宣告式 DSL,把一批資料(ActiveRecord relation、Struct 陣列,或任何有 `each` 的物件)匯出成 **CSV** 或 **XLSX**(透過較底層的 exporter,也能匯出舊版 **XLS**)。
6
7
 
7
- ## Installation
8
+ 你只要在 `ExportTo::Base` 的子類別裡宣告一次欄位(標題、來源屬性、寬度、格式、值的轉換),需要計算欄位時可以加上 presenter,也可以加上 `joins` relation 把一筆資料展開成多列,最後呼叫 `to_csv` / `to_xlsx` 即可。
8
9
 
9
- Add this line to your application's Gemfile:
10
+ ## 環境需求
11
+
12
+ | Ruby | CI 測試的 Rails / ActiveSupport 版本 |
13
+ |------|------------------------------------|
14
+ | 2.7 | 6.1 |
15
+ | 3.0 | 6.1, 7.0 |
16
+ | 3.1 | 6.1, 7.0, 7.1 |
17
+ | 3.2 | 7.0, 7.1 |
18
+ | 3.3 | 7.1, 8.0, 8.1 |
19
+ | 3.4 | 8.0, 8.1 |
20
+
21
+ gemspec 要求 Ruby `>= 2.7.0` 與 `activesupport >= 6.0, < 8.2`。實際支援範圍以 [`.github/workflows/ci.yml`](.github/workflows/ci.yml) 為準。
22
+
23
+ Runtime 相依套件:`fast_excel`(XLSX)、`spreadsheet`(XLS)、`csv`、`iconv`、`activesupport`。
24
+
25
+ ## 安裝
26
+
27
+ 在應用程式的 Gemfile 加入這一行:
10
28
 
11
29
  ```ruby
12
- gem 'export_to'
30
+ gem "export_to"
13
31
  ```
14
32
 
15
- And then execute:
33
+ 然後執行:
16
34
 
17
- $ bundle
35
+ ```bash
36
+ bundle install
37
+ ```
18
38
 
19
- Or install it yourself as:
39
+ 或自行執行 `gem install export_to` 安裝。
20
40
 
21
- $ gem install export_to
41
+ ## 使用方式
22
42
 
23
- ## Usage
43
+ ### 1. 定義 exporter
24
44
 
25
- TODO: Write usage instructions here
45
+ ```ruby
46
+ class UserExport < ExportTo::Base
47
+ # set <標題>, <key>, <欄位選項>, &可選的轉換 block
48
+ set "Name", :full_name, width: 30
49
+ set "Mobile", :mobile, width: 20, format: { bold: true }
50
+ set "Amount", :amount, width: 12 do |value|
51
+ value + 100 # block 會收到儲存格的值,並回傳最終要輸出的值
52
+ end
53
+ set "Source", "web" # key 為 String 時,每一列都會寫入這個固定值
54
+
55
+ excel worksheet: "Users", height: 24 # 可選的 XLSX 設定(工作表名稱、列高)
56
+
57
+ presenter do # 可選:計算欄位
58
+ def full_name
59
+ "#{first_name} #{last_name}" # 找不到的方法會委派給該筆 record
60
+ end
61
+
62
+ def amount
63
+ relation? ? relation.amount : 0
64
+ end
65
+ end
66
+
67
+ joins :wallets # 可選:record.wallets 裡每一筆各佔一列
68
+ end
69
+ ```
26
70
 
27
- ## Ruby & Rails Version Support
71
+ - **`set(title, key, options = {}, &block)`**:每次呼叫新增一個欄位,依呼叫順序排列。
72
+ - `key` 為 **Symbol** 時,會從 presenter 讀取(presenter 會委派給 record);`nil` 會變成 `""`。
73
+ - `key` 為 **String** 時,直接當作固定內容使用。
74
+ - XLSX 專用的 `options`:`width:`(欄寬)與 `format:`(`FastExcel` 的 format hash,例如 `{ bold: true }`)。
75
+ - 可選的 block 用來後處理儲存格的值。
76
+ - **`excel(worksheet: "Name", height: 20)`**:工作表名稱(預設 `"Default"`)與資料列的列高(預設 `20`)。標題列為粗體、置中並帶有背景色。
77
+ - **`presenter { ... }`**:定義 `YourExport::Presenter`(是上層 exporter 的 presenter 的子類別)。在裡面可以使用 `model`、`relation`、`relation?`、`x`(record 的索引)與 `y`(`joins` relation 內的索引)。
78
+ - **`joins(:relation_name)`**:當 `record.relation_name` 有資料時,每個元素各自成為一列,且 `relation` 就是該元素;presenter 會先找 `relation` 上的方法,找不到再找 `model`。relation 為空的 record 會產生單獨一列(此時 `relation?` 為 `false`)。
79
+ - **`each_with { |presenter| ... }`**:hook,會在讀取各欄位之前,以每一列的 presenter 呼叫一次。
80
+ - **`self.each_method = :find_in_batches`**:改用 `records.find_in_batches` 而不是 `records.each` 來迭代,適合很大的 ActiveRecord relation。
28
81
 
29
- This gem supports:
30
- - Ruby 2.7 with Rails 6.1
31
- - Ruby 3.0 with Rails 6.1, 7.0
32
- - Ruby 3.1 with Rails 6.1, 7.0, 7.1
33
- - Ruby 3.2 with Rails 7.0, 7.1
34
- - Ruby 3.3 with Rails 7.1
82
+ ### 2. 匯出
35
83
 
36
- ## Development
84
+ ```ruby
85
+ users = User.includes(:wallets).where(active: true) # 或任何可列舉的物件
86
+ export = UserExport.new(users)
37
87
 
38
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
88
+ export.to_csv # => String,每個欄位都有加引號("Name","Mobile",...)
89
+ export.to_xlsx # => .xlsx 檔案的二進位 String
90
+ export.each # => 所有列組成的 Array,第一列是標題列:[["Name", "Mobile", ...], ["Eddie Li", ...], ...]
91
+ export.each { |columns| ... } # 逐列 yield(第一列是標題列),並回傳 exporter 本身;Enumerable 方法也能用
92
+ ```
39
93
 
40
- ### Testing Multiple Ruby Versions
94
+ 兩位使用者的 CSV 輸出範例(第二位有兩個 wallet):
41
95
 
42
- To test against all supported Ruby versions at once:
96
+ ```
97
+ "Name","Mobile","Amount","Source"
98
+ "Eddie Li","+8869","100","web"
99
+ "Vegeta Lu","+8868","1100","web"
100
+ "Vegeta Lu","+8868","2100","web"
101
+ ```
102
+
103
+ 在 Rails controller 裡提供下載:
104
+
105
+ ```ruby
106
+ def export
107
+ send_data UserExport.new(User.all).to_xlsx,
108
+ filename: "users.xlsx",
109
+ type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
110
+ end
111
+ ```
112
+
113
+ ### 已知限制
114
+
115
+ 以下是目前程式碼的實際行為:
116
+
117
+ - `ExportTo::Base#to_xls` **已棄用,而且名稱有誤導性**:自 1.0.0 起它回傳的是與 `#to_xlsx` 相同的 **XLSX** 資料(不是舊版 `.xls` 檔)。保留這個行為是為了不讓既有呼叫端壞掉;呼叫時會印出一次性的 `[DEPRECATION]` 警告。請改用 `#to_xlsx`。若需要真正的舊版 `.xls` 檔,請用 `ExportTo::Exporter::Xls.new(export).to_xls`(不會套用任何樣式選項)。
118
+ - `width:` / `format:` 與 `excel` 選項只對 XLSX 輸出有效。
119
+ - 子類別會共用上層 class 的欄位定義陣列(`class_attribute`),所以如果某個 exporter 本身也會單獨使用,就不要在它的子類別裡呼叫 `set`。
120
+
121
+ ## 開發
122
+
123
+ clone 下來之後,先執行 `bin/setup` 安裝相依套件,接著跑測試:
43
124
 
44
125
  ```bash
45
- bin/test_all
126
+ bundle exec rake test # 也可以用 rake t / rake(預設 task)
127
+ bin/console # 互動式 console
46
128
  ```
47
129
 
48
- To check dependency compatibility:
130
+ 每個 Ruby / Rails 組合在 `gemfiles/` 內都有各自的 gemfile(CI 會把 `BUNDLE_GEMFILE` 指到它):
49
131
 
50
132
  ```bash
51
- bin/check_dependencies
133
+ BUNDLE_GEMFILE=$PWD/gemfiles/ruby_3.4_rails_8.1.gemfile bundle install
134
+ BUNDLE_GEMFILE=$PWD/gemfiles/ruby_3.4_rails_8.1.gemfile bundle exec rake test
52
135
  ```
53
136
 
54
- For more detailed testing instructions, see [TESTING.md](TESTING.md).
137
+ `bin/test_all` 會跑過所有支援的 Ruby 版本(需要 rbenv 或 rvm),`bin/check_dependencies` 會檢查相依套件的相容性;詳見 [TESTING.md](TESTING.md)。
138
+
139
+ ## 發版
140
+
141
+ 發版透過 RubyGems [Trusted Publishing](https://guides.rubygems.org/trusted-publishing/) 自動完成(repo 內不存放任何 API key):
142
+
143
+ 1. 在你的 PR 裡修改 `lib/export_to/version.rb` 的 `ExportTo::VERSION`(遵循 [Semantic Versioning](https://semver.org/lang/zh-TW/):修 bug 跳 patch、相容的新功能跳 minor、不相容的變更跳 major)。
144
+ 2. 在 `CHANGELOG.md` 新增對應的 `## [x.y.z] - YYYY-MM-DD` 區塊。
145
+ 3. 由真人 review 後合併進 `master`(AI 帳號只能開 PR)。
146
+ 4. [`.github/workflows/publish.yml`](.github/workflows/publish.yml) 會在 `master` 上執行:如果 gemspec 的版本還沒上 rubygems.org,就執行 `rake release`(打包 gem、打 `vX.Y.Z` tag、發佈)。沒有跳版號的合併不會發佈任何東西。
55
147
 
56
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
148
+ 只改文件 / CI 的 PR 不需要跳版號。請見 [CLAUDE.md](CLAUDE.md):每個 PR 也都必須更新 `README.md`(行為或用法有變時)並在 `CHANGELOG.md` 新增一筆條目。
57
149
 
58
- ## Contributing
150
+ ## 貢獻
59
151
 
60
- Bug reports and pull requests are welcome on GitHub at https://github.com/superlanding/export_to.
152
+ 歡迎到 GitHub 回報問題與提交 pull request:https://github.com/superlanding/export_to。
61
153
 
62
- ## License
154
+ ## 授權
63
155
 
64
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
156
+ 本 gem 以 [MIT License](https://opensource.org/licenses/MIT) 條款開源。
data/TESTING.md CHANGED
@@ -1,103 +1,45 @@
1
1
  # Testing Guide
2
2
 
3
- This gem supports multiple Ruby and Rails versions:
4
- - Ruby 2.7 with Rails 6.1
5
- - Ruby 3.0 with Rails 6.1, 7.0
6
- - Ruby 3.1 with Rails 6.1, 7.0, 7.1
3
+ Tests use Minitest + shoulda-context (`test/**/*_test.rb`) and run against several Ruby / Rails combinations.
7
4
 
8
- ## Multi-Version Testing
5
+ The supported matrix is defined in **one place**: [`.github/workflows/ci.yml`](.github/workflows/ci.yml). Each combination has a gemfile `gemfiles/ruby_<ruby>_rails_<rails>.gemfile`. Lists of versions are intentionally not copied here so they cannot go stale; see the [README](README.md#requirements) for the current table.
9
6
 
10
- ### Local Testing
7
+ ## Run the tests for one combination
11
8
 
12
- #### Test all Ruby versions at once
13
-
14
- Run the test suite against all supported Ruby versions:
9
+ CI selects the gemfile with `BUNDLE_GEMFILE`; do the same locally (switch to the matching Ruby first, e.g. with rbenv):
15
10
 
16
11
  ```bash
17
- bin/test_all
12
+ export BUNDLE_GEMFILE=$PWD/gemfiles/ruby_3.4_rails_8.1.gemfile
13
+ bundle install
14
+ bundle exec rake test # also: rake t / rake
18
15
  ```
19
16
 
20
- This script will:
21
- - Automatically switch between Ruby versions (requires rbenv or rvm)
22
- - Install dependencies for each version
23
- - Run the test suite for each version
24
- - Display a summary of results
25
-
26
- #### Test a specific Ruby/Rails version combination
17
+ ## Run the whole CI matrix locally
27
18
 
28
19
  ```bash
29
- # Ruby 2.7 with Rails 6.1
30
- export BUNDLE_GEMFILE=gemfiles/ruby_2.7_rails_6.1.gemfile
31
- bundle install
32
- bundle exec rake test
33
-
34
- # Ruby 3.0 with Rails 6.1
35
- export BUNDLE_GEMFILE=gemfiles/ruby_3.0_rails_6.1.gemfile
36
- bundle install
37
- bundle exec rake test
38
-
39
- # Ruby 3.0 with Rails 7.0
40
- export BUNDLE_GEMFILE=gemfiles/ruby_3.0_rails_7.0.gemfile
41
- bundle install
42
- bundle exec rake test
43
-
44
- # Ruby 3.1 with Rails 7.1
45
- export BUNDLE_GEMFILE=gemfiles/ruby_3.1_rails_7.1.gemfile
46
- bundle install
47
- bundle exec rake test
20
+ bin/test_all
48
21
  ```
49
22
 
50
- ### Dependency Checking
23
+ `bin/test_all` needs rbenv or rvm. For every entry of its `TEST_MATRIX` (kept equal to the CI matrix) it switches to the newest installed patch version of that Ruby, runs `bundle install` with the matching gemfile, runs `rake test` and prints a summary. A Ruby that is not installed is reported as a failure. When you change `ci.yml`, update `TEST_MATRIX` in `bin/test_all` as well.
51
24
 
52
- Check if all dependencies are compatible with all Ruby versions:
25
+ ## Check dependencies
53
26
 
54
27
  ```bash
55
28
  bin/check_dependencies
56
29
  ```
57
30
 
58
- This script will verify that all dependencies can be installed and will report any outdated gems.
59
-
60
- ## CI/CD
61
-
62
- The gem uses GitHub Actions for continuous integration. Every push and pull request will automatically test against all supported combinations:
63
- - Ruby 2.7 / Rails 6.1
64
- - Ruby 3.0 / Rails 6.1, 7.0
65
- - Ruby 3.1 / Rails 6.1, 7.0, 7.1
66
-
67
- See `.github/workflows/ci.yml` for the full configuration.
68
-
69
- ## Gemfiles Structure
70
-
71
- The `gemfiles/` directory contains version-specific Gemfiles for each Ruby/Rails combination:
72
- - `ruby_2.7_rails_6.1.gemfile` - Ruby 2.7 with Rails 6.1
73
- - `ruby_3.0_rails_6.1.gemfile` - Ruby 3.0 with Rails 6.1
74
- - `ruby_3.0_rails_7.0.gemfile` - Ruby 3.0 with Rails 7.0
75
- - `ruby_3.1_rails_6.1.gemfile` - Ruby 3.1 with Rails 6.1
76
- - `ruby_3.1_rails_7.0.gemfile` - Ruby 3.1 with Rails 7.0
77
- - `ruby_3.1_rails_7.1.gemfile` - Ruby 3.1 with Rails 7.1
31
+ Verifies that the dependencies can be installed for the supported versions and reports outdated gems.
78
32
 
79
- Each gemfile has its own lockfile committed to the repository to ensure consistent dependency versions across environments.
33
+ ## Adding a Ruby / Rails combination
80
34
 
81
- ## Requirements
35
+ 1. Add `gemfiles/ruby_<ruby>_rails_<rails>.gemfile` (copy a neighbouring one and change the `activesupport` / `railties` versions).
36
+ 2. Add the combination to the matrix in `.github/workflows/ci.yml` and to `TEST_MATRIX` in `bin/test_all`.
37
+ 3. Update the table in the README.
82
38
 
83
- ### For Local Multi-Version Testing
39
+ ## Lockfiles
84
40
 
85
- You need either:
86
- - **rbenv** with Ruby 2.7, 3.0, and 3.1 installed
87
- - **rvm** with Ruby 2.7, 3.0, and 3.1 installed
41
+ Some gemfiles have a committed `*.gemfile.lock`, and `Gemfile.lock` is committed too. They contain the gem's own version (`export_to (x.y.z)`), so **keep them consistent: bump the version in those files whenever `lib/export_to/version.rb` changes**.
88
42
 
89
- ### Installing Ruby Versions
43
+ ## CI
90
44
 
91
- #### Using rbenv:
92
- ```bash
93
- rbenv install 2.7.8
94
- rbenv install 3.0.6
95
- rbenv install 3.1.4
96
- ```
97
-
98
- #### Using rvm:
99
- ```bash
100
- rvm install 2.7.8
101
- rvm install 3.0.6
102
- rvm install 3.1.4
103
- ```
45
+ GitHub Actions runs every matrix entry on every push to `master` and on every pull request that targets `master`.
data/bin/test_all CHANGED
@@ -6,13 +6,22 @@
6
6
  set -e
7
7
 
8
8
  # Define test matrix: ruby_version:rails_version
9
+ # Keep in sync with the matrix in .github/workflows/ci.yml (and gemfiles/).
10
+ # ruby_version is "major.minor"; the newest installed patch version is used.
9
11
  TEST_MATRIX=(
10
- "2.7.6:6.1"
11
- "3.0.7:6.1"
12
- "3.0.7:7.0"
13
- "3.1.7:6.1"
14
- "3.1.7:7.0"
15
- "3.1.7:7.1"
12
+ "2.7:6.1"
13
+ "3.0:6.1"
14
+ "3.0:7.0"
15
+ "3.1:6.1"
16
+ "3.1:7.0"
17
+ "3.1:7.1"
18
+ "3.2:7.0"
19
+ "3.2:7.1"
20
+ "3.3:7.1"
21
+ "3.3:8.0"
22
+ "3.3:8.1"
23
+ "3.4:8.0"
24
+ "3.4:8.1"
16
25
  )
17
26
 
18
27
  SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
@@ -60,13 +69,14 @@ for test_case in "${TEST_MATRIX[@]}"; do
60
69
 
61
70
  # Set Ruby version
62
71
  if [ "$RUBY_MANAGER" == "rbenv" ]; then
63
- if ! rbenv versions | grep -q "^[* ]*${ruby_version}"; then
72
+ installed_version="$(rbenv versions --bare | grep -E "^${ruby_version//./\\.}\\." | sort -V | tail -n 1)"
73
+ if [ -z "${installed_version}" ]; then
64
74
  echo -e "${RED}Ruby ${ruby_version} not installed in rbenv. Skipping...${NC}"
65
75
  FAILED=$((FAILED + 1))
66
76
  FAILED_TESTS+=("Ruby ${ruby_version} / Rails ${rails_version} (Ruby not installed)")
67
77
  continue
68
78
  fi
69
- export RBENV_VERSION="${ruby_version}"
79
+ export RBENV_VERSION="${installed_version}"
70
80
  elif [ "$RUBY_MANAGER" == "rvm" ]; then
71
81
  if ! rvm list | grep -q "ruby-${ruby_version}"; then
72
82
  echo -e "${RED}Ruby ${ruby_version} not installed in rvm. Skipping...${NC}"
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- export_to (1.2.1)
4
+ export_to (1.3.0)
5
5
  activesupport (>= 6.0, < 8.2)
6
6
  csv
7
7
  fast_excel (~> 0.4)
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- export_to (1.2.1)
4
+ export_to (1.3.0)
5
5
  activesupport (>= 6.0, < 8.2)
6
6
  csv
7
7
  fast_excel (~> 0.4)
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- export_to (1.2.1)
4
+ export_to (1.3.0)
5
5
  activesupport (>= 6.0, < 8.2)
6
6
  csv
7
7
  fast_excel (~> 0.4)
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- export_to (1.2.1)
4
+ export_to (1.3.0)
5
5
  activesupport (>= 6.0, < 8.2)
6
6
  csv
7
7
  fast_excel (~> 0.4)
@@ -183,7 +183,7 @@ CHECKSUMS
183
183
  drb (2.2.3) sha256=0b00d6fdb50995fe4a45dea13663493c841112e4068656854646f418fda13373
184
184
  erb (6.0.7) sha256=c5ca6dc25b0ef974a44dc8f59fe847577122483b1968a38dec305c60bf91ee92
185
185
  erubi (1.13.1) sha256=a082103b0885dbc5ecf1172fede897f9ebdb745a4b97a5e8dc63953db1ee4ad9
186
- export_to (1.2.1)
186
+ export_to (1.3.0)
187
187
  fast_excel (0.5.0) sha256=59c418bdcf586a6030798d4e3a9f575742badaceaf7bb90f38eee5feb5bdc478
188
188
  ffi (1.17.4-aarch64-linux-gnu) sha256=b208f06f91ffd8f5e1193da3cae3d2ccfc27fc36fba577baf698d26d91c080df
189
189
  ffi (1.17.4-aarch64-linux-musl) sha256=9286b7a615f2676245283aef0a0a3b475ae3aae2bb5448baace630bb77b91f39
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- export_to (1.2.1)
4
+ export_to (1.3.0)
5
5
  activesupport (>= 6.0, < 8.2)
6
6
  csv
7
7
  fast_excel (~> 0.4)
@@ -182,7 +182,7 @@ CHECKSUMS
182
182
  drb (2.2.3) sha256=0b00d6fdb50995fe4a45dea13663493c841112e4068656854646f418fda13373
183
183
  erb (6.0.7) sha256=c5ca6dc25b0ef974a44dc8f59fe847577122483b1968a38dec305c60bf91ee92
184
184
  erubi (1.13.1) sha256=a082103b0885dbc5ecf1172fede897f9ebdb745a4b97a5e8dc63953db1ee4ad9
185
- export_to (1.2.1)
185
+ export_to (1.3.0)
186
186
  fast_excel (0.5.0) sha256=59c418bdcf586a6030798d4e3a9f575742badaceaf7bb90f38eee5feb5bdc478
187
187
  ffi (1.17.4-aarch64-linux-gnu) sha256=b208f06f91ffd8f5e1193da3cae3d2ccfc27fc36fba577baf698d26d91c080df
188
188
  ffi (1.17.4-aarch64-linux-musl) sha256=9286b7a615f2676245283aef0a0a3b475ae3aae2bb5448baace630bb77b91f39
@@ -25,17 +25,25 @@ module ExportTo
25
25
  ExportTo::Exporter::Xlsx.new(self).export
26
26
  end
27
27
 
28
- # 舊版 Excel
28
+ # 注意:名稱叫 xls,但自 1.0.0 起實際回傳的是 XLSX 內容(與 #to_xlsx 相同),
29
+ # 為了不破壞既有呼叫端,行為維持不變,僅在第一次呼叫時印出 deprecation 警告。
30
+ # 請改用 #to_xlsx;需要真正的舊版 .xls 請用 ExportTo::Exporter::Xls.new(export).to_xls
29
31
  def to_xls
30
- ExportTo::Exporter::Xlsx.new(self).export
32
+ self.class.warn_to_xls_deprecated(caller_locations(1, 1).first)
33
+ to_xlsx
31
34
  end
32
35
 
36
+ # 回傳所有列(第一列是表頭)的二維陣列,與 CSV / XLSX 看到的內容一致。
37
+ # 給 block 時逐列 yield columns 並回傳 self(Enumerable 的方法因此可用)。
33
38
  def each
34
39
  data = []
35
- rows! do |columns, model, x|
40
+ each! do |columns, _model, _index|
36
41
  data.push(columns)
37
42
  end
38
- data
43
+ return data unless block_given?
44
+
45
+ data.each { |columns| yield(columns) }
46
+ self
39
47
  end
40
48
 
41
49
  def each!
@@ -92,6 +100,16 @@ module ExportTo
92
100
  end
93
101
 
94
102
  class << self
103
+ # to_xls 只警告一次(每個 process),避免洗版 log
104
+ def warn_to_xls_deprecated(location = nil)
105
+ return if Base.to_xls_warned
106
+ Base.to_xls_warned = true
107
+ where = location ? " (called from #{location})" : ""
108
+ Kernel.warn "[DEPRECATION] ExportTo::Base#to_xls returns XLSX data, not a legacy .xls file; " \
109
+ "use #to_xlsx instead. #to_xls keeps this behavior for compatibility#{where}."
110
+ end
111
+
112
+ attr_accessor :to_xls_warned
95
113
 
96
114
  protected
97
115
 
@@ -1,3 +1,3 @@
1
1
  module ExportTo
2
- VERSION = "1.2.1"
2
+ VERSION = "1.3.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: export_to
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - eddie
@@ -152,6 +152,7 @@ files:
152
152
  - ".github/workflows/publish.yml"
153
153
  - ".gitignore"
154
154
  - ".travis.yml"
155
+ - CHANGELOG.md
155
156
  - CLAUDE.md
156
157
  - Gemfile
157
158
  - Gemfile.lock