file_annotate 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4a0082d2dceab828995d5ceaf298423e28d57eedf5670049e394bd6edf40f3dd
4
+ data.tar.gz: 6a2a3e956cc4652add4225080c4d4b15628de0ec3e5076f307748f92787d151a
5
+ SHA512:
6
+ metadata.gz: f6c851f1c078abe2143b7424b3b62ca929c6db8ec3d827644f11c513352e7732c4bc1635c575c62ea4fba613ef4f9e11e87f9ad9b7c1fbe4897184848138566c
7
+ data.tar.gz: fbb2662517dcaf9ca36725a1a61dd0d949bdd6d6f575b6b41b593f65ee20db4d7c6a6572c20b88540178b035bb8f1e1071b3e81ef301cbd86e5a98b3512826d8
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,22 @@
1
+ AllCops:
2
+ TargetRubyVersion: 3.0
3
+ SuggestExtensions: false
4
+
5
+ Style/StringLiterals:
6
+ EnforcedStyle: double_quotes
7
+
8
+ Style/StringLiteralsInInterpolation:
9
+ EnforcedStyle: double_quotes
10
+
11
+ Style/AsciiComments:
12
+ Enabled: false
13
+
14
+ Metrics/BlockLength:
15
+ Enabled: false
16
+
17
+ require:
18
+ - ./lib/rubocop/cop/file_annotate/first_line_comment.rb
19
+
20
+ FileAnnotate/FirstLineComment:
21
+ Enabled: true
22
+ EnforcedStyle: forbidden # default is 'required', can be 'forbidden'
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2025-03-03
4
+
5
+ - Initial release
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 jedivulyliu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # FileAnnotate 檔案路徑註解套件
2
+
3
+ FileAnnotate 是一個 Ruby Gem,提供兩大功能:
4
+
5
+ CLI 批次處理:自動在專案內每個 .rb 檔案的第一行插入該檔案路徑的註解。
6
+
7
+ RuboCop 插件:提供自訂 Cop,檢查並確保 .rb 檔案第一行為正確的檔案路徑註解,並支援自動修正。
8
+
9
+ ## Installation 安裝方式
10
+
11
+ 在專案的 Gemfile 中加入:
12
+ ```ruby
13
+ gem "file_annotate"
14
+ ```
15
+ 然後執行:
16
+ ```bash
17
+ bundle install
18
+ ```
19
+ 或是直接安裝:
20
+ ```bash
21
+ gem install file_annotate
22
+ ```
23
+
24
+ ## Usage 使用說明
25
+
26
+ ✅ CLI 批次處理
27
+ 執行以下指令,會自動為專案中所有 .rb 檔案加上第一行檔案路徑註解:
28
+ ```bash
29
+ file_annotate add
30
+ ```
31
+
32
+ 執行以下指令,會自動檢查專案中所有 .rb 檔案的第一行或第二行為檔案路徑註解時,給予刪除:
33
+ ```bash
34
+ file_annotate remove
35
+ ```
36
+
37
+ ✅ RuboCop 規則檢查
38
+ 在你的專案 .rubocop.yml 檔案中加入:
39
+ ```yaml
40
+ require:
41
+ - file_annotate/rubocop
42
+
43
+ FileAnnotate/FirstLineComment:
44
+ Enabled: true
45
+ ```
46
+
47
+ 然後執行 RuboCop:
48
+ ```bash
49
+ rubocop
50
+ ```
51
+
52
+ 若需要自動修正缺少的檔案註解,請使用:
53
+ ```bash
54
+ rubocop -A
55
+ ```
56
+
57
+ ## Contributing
58
+
59
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/file_annotate.
60
+
61
+ ## License
62
+
63
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require "rubocop/rake_task"
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[spec rubocop]
data/bin/file_annotate ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # bin/file_annotate
5
+
6
+ require "file_annotate"
7
+
8
+ FileAnnotate::CLI.start
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FileAnnotate
4
+ # 負責對檔案內容進行註解的處理
5
+ class Annotator
6
+ def self.annotate_all
7
+ each_rb_file do |file|
8
+ lines = File.readlines(file)
9
+ next if annotated?(lines, file)
10
+
11
+ insert_annotation!(lines, file)
12
+ File.write(file, lines.join)
13
+ end
14
+ end
15
+
16
+ def self.remove_all
17
+ each_rb_file do |file|
18
+ lines = File.readlines(file)
19
+ File.write(file, lines.join) if remove_annotation!(lines, file)
20
+ end
21
+ end
22
+
23
+ def self.each_rb_file(&block)
24
+ Dir.glob("**/*.rb").each(&block)
25
+ end
26
+
27
+ def self.annotation_text(file)
28
+ "# #{file}"
29
+ end
30
+
31
+ def self.annotated?(lines, file)
32
+ lines.first&.strip == annotation_text(file)
33
+ end
34
+
35
+ def self.insert_annotation!(lines, file)
36
+ lines.unshift("#{annotation_text(file)}\n")
37
+ end
38
+
39
+ def self.remove_annotation!(lines, file)
40
+ if annotated?(lines, file)
41
+ lines.delete_at(0)
42
+ true
43
+ else
44
+ false
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "thor"
4
+ require "file_annotate/annotator"
5
+
6
+ module FileAnnotate
7
+ # CLI 負責處理指令列操作
8
+ class CLI < Thor
9
+ desc "add", "批次將檔案路徑註解插入所有 .rb 檔案"
10
+ def add
11
+ puts "=== FileAnnotate CLI - Add file path comments ==="
12
+ FileAnnotate::Annotator.annotate_all
13
+ puts "Done!"
14
+ end
15
+
16
+ desc "remove", "批次移除所有檔案的檔案路徑註解"
17
+ def remove
18
+ puts "=== FileAnnotate CLI - Remove file path comments ==="
19
+ FileAnnotate::Annotator.remove_all
20
+ puts "Done!"
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../rubocop/cop/file_annotate/first_line_comment"
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FileAnnotate
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "file_annotate/version"
4
+ require_relative "file_annotate/cli"
5
+ require_relative "file_annotate/annotator"
6
+ require "rubocop"
7
+ require_relative "rubocop/cop/file_annotate/first_line_comment"
8
+
9
+ module FileAnnotate
10
+ class Error < StandardError; end
11
+ # Your code goes here...
12
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pathname'
4
+
5
+ module RuboCop
6
+ module Cop
7
+ module FileAnnotate
8
+ # 檢查檔案開頭的相對路徑註解是否符合設定
9
+ class FirstLineComment < Base
10
+ extend AutoCorrector
11
+
12
+ MSG_MISSING = "Missing file path comment."
13
+ MSG_FORBIDDEN = "File path comment is forbidden on the first line."
14
+
15
+ def on_new_investigation
16
+ return if processed_source.lines.empty?
17
+
18
+ @project_root = Pathname.pwd
19
+ @absolute_path = Pathname.new(processed_source.file_path)
20
+ @relative_path = @absolute_path.relative_path_from(@project_root).to_s
21
+ @expected_comment = "# #{@relative_path}"
22
+
23
+ case enforced_style
24
+ when :required
25
+ check_required
26
+ when :forbidden
27
+ check_forbidden
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def enforced_style
34
+ cop_config.fetch('EnforcedStyle', 'required').to_sym
35
+ end
36
+
37
+ def check_required
38
+ return if annotated_correctly?
39
+
40
+ position = 0 # 檔案開頭位置
41
+ range = Parser::Source::Range.new(processed_source.buffer, position, position)
42
+
43
+ add_offense(range, message: MSG_MISSING) do |corrector|
44
+ corrector.insert_before(range, "#{@expected_comment}\n")
45
+ end
46
+ end
47
+
48
+ def check_forbidden
49
+ first_line = processed_source.lines[0]&.strip
50
+ return unless first_line == @expected_comment
51
+
52
+ range = processed_source.buffer.line_range(1)
53
+ add_offense(range, message: MSG_FORBIDDEN) do |corrector|
54
+ corrector.remove(range_with_trailing_newline(range))
55
+ end
56
+ end
57
+
58
+ def annotated_correctly?
59
+ first_line = processed_source.lines[0]&.strip
60
+ first_line == @expected_comment
61
+ end
62
+
63
+ def range_with_trailing_newline(range)
64
+ buffer = processed_source.buffer
65
+ source = buffer.source
66
+ end_pos = range.end_pos
67
+ end_pos += 1 if source[end_pos] == "\n"
68
+ Parser::Source::Range.new(buffer, range.begin_pos, end_pos)
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,4 @@
1
+ module FileAnnotate
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: file_annotate
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - jedivulyliu
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2025-03-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rubocop
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.60'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.60'
27
+ - !ruby/object:Gem::Dependency
28
+ name: thor
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rubocop
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.60'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.60'
55
+ description: 批次掃描 .rb 檔案並加入路徑註解,並支援 RuboCop 檢查
56
+ email:
57
+ - jedivuly@gmail.com
58
+ executables:
59
+ - file_annotate
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - ".rspec"
64
+ - ".rubocop.yml"
65
+ - CHANGELOG.md
66
+ - LICENSE.txt
67
+ - README.md
68
+ - Rakefile
69
+ - bin/file_annotate
70
+ - lib/file_annotate.rb
71
+ - lib/file_annotate/annotator.rb
72
+ - lib/file_annotate/cli.rb
73
+ - lib/file_annotate/rubocop.rb
74
+ - lib/file_annotate/version.rb
75
+ - lib/rubocop/cop/file_annotate/first_line_comment.rb
76
+ - sig/file_annotate.rbs
77
+ homepage: https://github.com/jedivuly/file_annotate
78
+ licenses:
79
+ - MIT
80
+ metadata:
81
+ allowed_push_host: https://rubygems.org
82
+ homepage_uri: https://github.com/jedivuly/file_annotate
83
+ source_code_uri: https://github.com/jedivuly/file_annotate
84
+ changelog_uri: https://github.com/jedivuly/file_annotate/blob/main/CHANGELOG.md
85
+ rubocop_extension: 'true'
86
+ post_install_message:
87
+ rdoc_options: []
88
+ require_paths:
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '3.0'
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ requirements: []
101
+ rubygems_version: 3.2.33
102
+ signing_key:
103
+ specification_version: 4
104
+ summary: 在 Ruby 檔案的第一行插入檔案路徑註解
105
+ test_files: []