remind_me 0.6.0 → 0.7.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: 3f76a53f49a07d6a0e777ef236281f87dff2e4881f83b8edcd7b18c5fb99dce3
4
- data.tar.gz: c6e765928f9020b17c035429dac9cb941e717c67fd07b700790e4c49f4f15129
3
+ metadata.gz: 7fa0e33f33da3bbe35b1245625c5c605c5e20d14e90f5c710676224245a456fa
4
+ data.tar.gz: 0bea7706ce46a895d36203bff906e245c5d42adf23c8b68d6e6f7a8de4255ec8
5
5
  SHA512:
6
- metadata.gz: 736d8b964280e45d6300c53c76ba476fc6bffc68262341d4fbc59f1cb139ac3333e327bdc9e680a1c4a94f0131e8ab1762e93649e18a13f5728f380cbbdc1c49
7
- data.tar.gz: 7e3fa1d5760d38f9d77e0172dc082e21c7b236d74451f57d0cdb00ad477cbca4c28113ff96d4dd5196f5c9d70b5269995926c66681c396042c5b8eb2e2f20576
6
+ metadata.gz: 4d59df0fa184b0166e0b246eca2e58b3e2ec3bdbf86a16d07f54298001a4b99c98410e3c6a41de5b57c46837ea875a651a5e520ac91bce78e8832977892babaf
7
+ data.tar.gz: 10e9483a5de777738edc140fd88db75d49a5133c466798e2212e670fcabd358995744e8c2e6e882559caa85817f1ea30b4e6c45823076e8544689e9714f3d862
@@ -1,40 +1,27 @@
1
1
  name: Tests
2
2
 
3
- on: [push,pull_request]
3
+ on: [push]
4
4
 
5
5
  jobs:
6
6
  build:
7
- runs-on: ubuntu-latest
7
+ runs-on: ${{ matrix.os }}
8
8
  strategy:
9
9
  fail-fast: false
10
10
  matrix:
11
- ruby: [ "2.3.7", "2.4.10", "2.5.9", "2.6.8", "2.7.4", "3.0.6", "3.1.4", "3.2.2", "jruby-9.2", "jruby-9.3", "jruby-9.4" ]
12
- include:
13
- - ruby: "2.3.7"
14
- requires-older-rubygems: true
15
- requires-older-bundler: true
16
- - ruby: "2.4.10"
17
- requires-older-rubygems: true
18
- requires-older-bundler: true
19
- - ruby: "jruby-9.2"
20
- requires-older-bundler: true
21
- - ruby: "jruby-9.3"
22
- requires-older-bundler: true
11
+ os: [ubuntu-latest, ubuntu-24.04-arm, macos-14]
12
+ # TODO: Add Ruby 4.0 and 4.1 once Magnus gem releases official support
13
+ ruby: ["2.7.8", "3.0.7", "3.1.7", "3.2.10", "3.3.10", "3.4.8"]
23
14
  steps:
24
- - uses: actions/checkout@v3
15
+ - uses: actions/checkout@v4
25
16
  - name: Set up Ruby
26
17
  uses: ruby/setup-ruby@v1
27
18
  with:
28
19
  ruby-version: ${{ matrix.ruby }}
29
- - if: ${{ matrix.requires-older-rubygems }}
30
- run: gem update --system 3.2.3
31
- - if: ${{ matrix.requires-older-bundler }}
32
- run: gem install bundler -v 2.3.26
20
+ - name: Install Rust toolchain
21
+ uses: dtolnay/rust-toolchain@stable
33
22
  - name: Bundle install
34
23
  run: bundle install --jobs=3
35
- - name: Run tests (MRI)
24
+ - name: Compile native extension
25
+ run: bundle exec rake compile
26
+ - name: Run tests
36
27
  run: bundle exec rake spec
37
- if: "!startsWith(matrix.ruby, 'jruby')"
38
- - name: Run tests (JRuby)
39
- run: JRUBY_OPTS=--debug bundle exec rake spec
40
- if: startsWith(matrix.ruby, 'jruby')
data/.gitignore CHANGED
@@ -12,4 +12,6 @@
12
12
  .rspec_status
13
13
  .ruby-version
14
14
  /*.gem
15
- /target/
15
+ /target/
16
+ ext/remind_me/target/
17
+ lib/remind_me/remind_me_native.*
data/CLAUDE.md ADDED
@@ -0,0 +1,57 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Project Overview
6
+
7
+ `remind_me` is a Ruby gem that provides a non-invasive code reminder system. It scans Ruby files for special `REMIND_ME:` comments (written as Ruby hash syntax) and checks whether specified conditions are met (gem versions, Ruby versions, missing gems). Designed to run in CI pipelines so developers revisit code when conditions are satisfied. Comments don't affect runtime behavior.
8
+
9
+ ## Common Commands
10
+
11
+ ```bash
12
+ bundle exec rake spec # Run tests
13
+ bundle exec rake rubocop # Run linter only
14
+ bundle exec rspec spec/remind_me/runner_spec.rb # Single test file
15
+ bundle exec rspec spec/remind_me/runner_spec.rb:42 # Single test by line
16
+ bundle exec rake compile # Compile Rust native extension
17
+ bundle exec rake install # Install gem locally
18
+ cargo test --manifest-path ext/remind_me/Cargo.toml # Run Rust unit tests
19
+ ```
20
+
21
+ Note: On Ruby 2.7 with bundler version conflicts, use `bundle _2.4.22_` prefix.
22
+
23
+ ## Architecture
24
+
25
+ **Entry point:** `lib/remind_me.rb` → loads `Runner` and optional `Railtie`
26
+
27
+ **Core flow:** `Runner.check_reminders()` → scans for `REMIND_ME:` comments → `Generator.generate()` creates reminder objects → `ResultPrinter.print_results()` reports or exits with error.
28
+
29
+ **Native Rust extension (optional):** When compiled (`rake compile`), a Rust extension (`ext/remind_me/`) using `ignore` (parallel dir walking) and `memchr` (fast string search) replaces the Ruby file scanning. Exposed as `RemindMe::Native.scan_for_remind_me_comments(path)` via Magnus. Falls back to pure Ruby (`parser` gem) if the extension isn't available (JRuby, no Rust toolchain). The data contract between scanning and processing is `[source_location_string, comment_text_string]` tuples.
30
+
31
+ **Plugin system with self-registration:** `BaseReminder` subclasses auto-register via `inherited` hook into `Generator`'s registry. New reminder types are added by subclassing `BaseReminder` and using the hash AST DSL (`apply_to_hash_with`, `validate_hash_ast`).
32
+
33
+ **Built-in reminder types:**
34
+ - `GemVersionReminder` — `{ gem: 'rails', version: '6', condition: :gte, message: '...' }`
35
+ - `RubyVersionReminder` — `{ ruby_version: '3', condition: :gte, message: '...' }`
36
+ - `MissingGemReminder` — `{ missing_gem: 'thor', message: '...' }`
37
+
38
+ **Key modules:**
39
+ - `HashAstManipulations` — DSL for declaring/validating hash keys in parsed AST nodes; generates accessor and validation methods dynamically
40
+ - `BailOut` — error handling mixin used across reminder classes
41
+ - `Utils::Versions` — version comparison logic supporting operators: `lt`, `lte`, `gt`, `gte`, `eq`
42
+
43
+ **Parallel processing:** Uses `parallel` gem for concurrent reminder processing. Handles older parallel gem API differences. File scanning parallelism is handled by the Rust extension (or `parallel` in fallback mode).
44
+
45
+ **Rails integration:** `Railtie` auto-loads `remind_me:check_reminders` rake task when Rails is present.
46
+
47
+ ## Test Structure
48
+
49
+ Tests use RSpec with SimpleCov (90% overall minimum, 80% per-file). Fixture files live in `spec/testing_grounds/` organized by `single_line/` and `multi_line/` comment styles. The `runner_spec.rb` is the main integration test; unit tests are organized by reminder type under `spec/remind_me/reminder/`.
50
+
51
+ ## Style
52
+
53
+ RuboCop config: single quotes (double for interpolation), 120-char line limit, 14 method length limit. Documentation cop disabled for specs.
54
+
55
+ ## CI
56
+
57
+ GitHub Actions has two jobs: `build` (pure Ruby, all Ruby versions 2.3.7–3.2.2 + JRuby 9.2–9.4) and `build-native` (with Rust extension, Ruby 2.7.4–3.2.2).
data/Cargo.toml ADDED
@@ -0,0 +1,3 @@
1
+ [workspace]
2
+ members = ["ext/remind_me"]
3
+ resolver = "2"
data/Gemfile CHANGED
@@ -3,3 +3,6 @@
3
3
  source 'https://rubygems.org'
4
4
 
5
5
  gemspec
6
+
7
+ gem 'rake-compiler'
8
+ gem 'rb_sys'
data/README.md CHANGED
@@ -126,7 +126,7 @@ require 'remind_me'
126
126
 
127
127
  desc 'picks up REMIND_ME comments from codebase and checks if their conditions are met'
128
128
  task custom_check_reminders: :environment do
129
- RemindMe::Runner.new.check_reminders(check_path: '/some/other/directory/')
129
+ RemindMe::Runner.check_reminders(check_path: '/some/other/directory/')
130
130
  end
131
131
  ```
132
132
 
data/Rakefile CHANGED
@@ -9,4 +9,13 @@ require 'rubocop/rake_task'
9
9
 
10
10
  RuboCop::RakeTask.new
11
11
 
12
+ begin
13
+ require 'rb_sys/extensiontask'
14
+ RbSys::ExtensionTask.new('remind_me_native') do |ext|
15
+ ext.lib_dir = 'lib/remind_me'
16
+ end
17
+ rescue LoadError
18
+ # rb_sys not available, skip native extension compilation task
19
+ end
20
+
12
21
  task default: %i[spec rubocop]
@@ -0,0 +1,22 @@
1
+ [package]
2
+ name = "remind_me_native"
3
+ version = "0.7.0"
4
+ edition = "2021"
5
+ publish = false
6
+
7
+ [lib]
8
+ crate-type = ["cdylib", "rlib"]
9
+
10
+ [[bin]]
11
+ name = "bench"
12
+ path = "src/bench.rs"
13
+ required-features = []
14
+
15
+ [features]
16
+ default = ["ruby"]
17
+ ruby = ["magnus"]
18
+
19
+ [dependencies]
20
+ magnus = { version = "0.7", features = ["rb-sys"], optional = true }
21
+ ignore = "0.4"
22
+ memchr = "2"
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mkmf'
4
+
5
+ if system('cargo --version > /dev/null 2>&1')
6
+ require 'rb_sys/mkmf'
7
+ create_rust_makefile('remind_me/remind_me_native')
8
+ else
9
+ File.write('Makefile', "all:\ninstall:\n")
10
+ $stderr.puts 'WARNING: Rust toolchain not found, skipping native extension build. Using pure-Ruby fallback.'
11
+ end
@@ -0,0 +1,35 @@
1
+ use std::env;
2
+ use std::time::Instant;
3
+
4
+ use remind_me_native::scanner;
5
+
6
+ fn main() {
7
+ let path = env::args()
8
+ .nth(1)
9
+ .unwrap_or_else(|| ".".to_string());
10
+ let iterations: usize = env::args()
11
+ .nth(2)
12
+ .and_then(|s| s.parse().ok())
13
+ .unwrap_or(100);
14
+
15
+ println!("Scanning: {}", path);
16
+ println!("Iterations: {}", iterations);
17
+
18
+ // Warmup
19
+ let results = scanner::scan_for_remind_me_comments(&path);
20
+ println!("Found {} REMIND_ME comments", results.len());
21
+ for (loc, text) in &results {
22
+ println!(" {} {}", loc, text.trim());
23
+ }
24
+ println!();
25
+
26
+ // Benchmark
27
+ let start = Instant::now();
28
+ for _ in 0..iterations {
29
+ let _ = scanner::scan_for_remind_me_comments(&path);
30
+ }
31
+ let elapsed = start.elapsed();
32
+
33
+ println!("Total: {:.3}s ({} iterations)", elapsed.as_secs_f64(), iterations);
34
+ println!("Per iteration: {:.4}s", elapsed.as_secs_f64() / iterations as f64);
35
+ }
@@ -0,0 +1,21 @@
1
+ pub mod scanner;
2
+
3
+ #[cfg(feature = "ruby")]
4
+ use magnus::{function, prelude::*, Error, Ruby};
5
+
6
+ #[cfg(feature = "ruby")]
7
+ fn scan_for_remind_me_comments(path: String) -> Result<Vec<(String, String)>, Error> {
8
+ Ok(scanner::scan_for_remind_me_comments(&path))
9
+ }
10
+
11
+ #[cfg(feature = "ruby")]
12
+ #[magnus::init]
13
+ fn init(ruby: &Ruby) -> Result<(), Error> {
14
+ let module = ruby.define_module("RemindMe")?;
15
+ let native = module.define_module("Native")?;
16
+ native.define_module_function(
17
+ "scan_for_remind_me_comments",
18
+ function!(scan_for_remind_me_comments, 1),
19
+ )?;
20
+ Ok(())
21
+ }
@@ -0,0 +1,206 @@
1
+ use memchr::memmem;
2
+ use std::fs;
3
+ use std::path::Path;
4
+ use std::sync::Mutex;
5
+
6
+ const MARKER: &str = "REMIND_ME:";
7
+ const MARKER_LEN: usize = 10; // "REMIND_ME:".len()
8
+
9
+ /// A single REMIND_ME comment match with its source location and text.
10
+ pub struct Match {
11
+ pub source_location: String,
12
+ pub comment_text: String,
13
+ }
14
+
15
+ /// Scan a single file for REMIND_ME comments.
16
+ ///
17
+ /// Handles both single-line (`# REMIND_ME: ...`) and block (`=begin`/`=end`) comments.
18
+ /// Returns matches as (source_location, comment_text) where:
19
+ /// - source_location is "path:line:1"
20
+ /// - comment_text is everything after "REMIND_ME:" on the matching line
21
+ pub fn scan_file(file_path: &str) -> Vec<Match> {
22
+ let content = match fs::read_to_string(file_path) {
23
+ Ok(c) => c,
24
+ Err(_) => return Vec::new(),
25
+ };
26
+
27
+ // Quick check: skip file entirely if no REMIND_ME: present
28
+ if memmem::find(content.as_bytes(), MARKER.as_bytes()).is_none() {
29
+ return Vec::new();
30
+ }
31
+
32
+ let lines: Vec<&str> = content.lines().collect();
33
+
34
+ // First pass: identify =begin/=end block comment boundaries
35
+ let mut block_ranges: Vec<(usize, usize)> = Vec::new();
36
+ let mut current_begin: Option<usize> = None;
37
+ for (i, line) in lines.iter().enumerate() {
38
+ if line.starts_with("=begin") && current_begin.is_none() {
39
+ current_begin = Some(i + 1); // 1-indexed
40
+ } else if line.starts_with("=end") {
41
+ if let Some(begin_line) = current_begin {
42
+ block_ranges.push((begin_line, i + 1));
43
+ current_begin = None;
44
+ }
45
+ }
46
+ }
47
+
48
+ // Second pass: find REMIND_ME: on each line
49
+ let finder = memmem::Finder::new(MARKER);
50
+ let mut results = Vec::new();
51
+
52
+ for (i, line) in lines.iter().enumerate() {
53
+ let line_num = i + 1; // 1-indexed
54
+
55
+ if let Some(pos) = finder.find(line.as_bytes()) {
56
+ let comment_text = &line[pos + MARKER_LEN..];
57
+
58
+ // Determine if this match is inside a comment
59
+ let in_block = block_ranges
60
+ .iter()
61
+ .any(|(begin, end)| line_num >= *begin && line_num <= *end);
62
+
63
+ if in_block {
64
+ // Block comment: report the =begin line number
65
+ let begin_line = block_ranges
66
+ .iter()
67
+ .find(|(begin, end)| line_num >= *begin && line_num <= *end)
68
+ .map(|(begin, _)| *begin)
69
+ .unwrap();
70
+
71
+ results.push(Match {
72
+ source_location: format!("{}:{}:1", file_path, begin_line),
73
+ comment_text: comment_text.to_string(),
74
+ });
75
+ } else if line[..pos].contains('#') {
76
+ // Single-line comment: # appears before REMIND_ME:
77
+ results.push(Match {
78
+ source_location: format!("{}:{}:1", file_path, line_num),
79
+ comment_text: comment_text.to_string(),
80
+ });
81
+ }
82
+ // Otherwise: REMIND_ME: in code/string, skip it
83
+ }
84
+ }
85
+
86
+ results
87
+ }
88
+
89
+ /// Walk a directory (or scan a single file) for REMIND_ME comments in .rb files.
90
+ /// Returns a Vec of (source_location, comment_text) tuples.
91
+ pub fn scan_for_remind_me_comments(path: &str) -> Vec<(String, String)> {
92
+ let p = Path::new(path);
93
+
94
+ if p.is_file() {
95
+ return scan_file(path)
96
+ .into_iter()
97
+ .map(|m| (m.source_location, m.comment_text))
98
+ .collect();
99
+ }
100
+
101
+ // Directory mode: parallel walk with ignore crate
102
+ let results: Mutex<Vec<(String, String)>> = Mutex::new(Vec::new());
103
+
104
+ ignore::WalkBuilder::new(path)
105
+ .hidden(false)
106
+ .git_ignore(false)
107
+ .git_global(false)
108
+ .git_exclude(false)
109
+ .build_parallel()
110
+ .run(|| {
111
+ Box::new(|entry| {
112
+ if let Ok(entry) = entry {
113
+ let entry_path = entry.path();
114
+ if entry_path.is_file()
115
+ && entry_path.extension().map_or(false, |ext| ext == "rb")
116
+ {
117
+ if let Some(path_str) = entry_path.to_str() {
118
+ let matches = scan_file(path_str);
119
+ if !matches.is_empty() {
120
+ let mut r = results.lock().unwrap();
121
+ for m in matches {
122
+ r.push((m.source_location, m.comment_text));
123
+ }
124
+ }
125
+ }
126
+ }
127
+ }
128
+ ignore::WalkState::Continue
129
+ })
130
+ });
131
+
132
+ results.into_inner().unwrap()
133
+ }
134
+
135
+ #[cfg(test)]
136
+ mod tests {
137
+ use super::*;
138
+
139
+ #[test]
140
+ fn test_single_line_comment() {
141
+ let content = "# some comment\n# REMIND_ME: { gem: 'rails' }\ncode here\n";
142
+ let tmp = std::env::temp_dir().join("test_single_line.rb");
143
+ fs::write(&tmp, content).unwrap();
144
+ let matches = scan_file(tmp.to_str().unwrap());
145
+ assert_eq!(matches.len(), 1);
146
+ assert!(matches[0].source_location.ends_with(":2:1"));
147
+ assert_eq!(matches[0].comment_text, " { gem: 'rails' }");
148
+ fs::remove_file(&tmp).ok();
149
+ }
150
+
151
+ #[test]
152
+ fn test_block_comment() {
153
+ let content = "=begin\n some text\n REMIND_ME: { gem: 'rails' }\n=end\n";
154
+ let tmp = std::env::temp_dir().join("test_block_comment.rb");
155
+ fs::write(&tmp, content).unwrap();
156
+ let matches = scan_file(tmp.to_str().unwrap());
157
+ assert_eq!(matches.len(), 1);
158
+ assert!(matches[0].source_location.ends_with(":1:1")); // points to =begin
159
+ assert_eq!(matches[0].comment_text, " { gem: 'rails' }");
160
+ fs::remove_file(&tmp).ok();
161
+ }
162
+
163
+ #[test]
164
+ fn test_remind_me_in_string_skipped() {
165
+ let content = "puts \"REMIND_ME: something\"\n";
166
+ let tmp = std::env::temp_dir().join("test_in_string.rb");
167
+ fs::write(&tmp, content).unwrap();
168
+ let matches = scan_file(tmp.to_str().unwrap());
169
+ assert_eq!(matches.len(), 0);
170
+ fs::remove_file(&tmp).ok();
171
+ }
172
+
173
+ #[test]
174
+ fn test_no_matches() {
175
+ let content = "# just a comment\nputs 'hello'\n";
176
+ let tmp = std::env::temp_dir().join("test_no_match.rb");
177
+ fs::write(&tmp, content).unwrap();
178
+ let matches = scan_file(tmp.to_str().unwrap());
179
+ assert_eq!(matches.len(), 0);
180
+ fs::remove_file(&tmp).ok();
181
+ }
182
+
183
+ #[test]
184
+ fn test_multiple_matches() {
185
+ let content = "# REMIND_ME: { gem: 'a' }\n# regular\n# REMIND_ME: { gem: 'b' }\n";
186
+ let tmp = std::env::temp_dir().join("test_multiple.rb");
187
+ fs::write(&tmp, content).unwrap();
188
+ let matches = scan_file(tmp.to_str().unwrap());
189
+ assert_eq!(matches.len(), 2);
190
+ assert!(matches[0].source_location.ends_with(":1:1"));
191
+ assert!(matches[1].source_location.ends_with(":3:1"));
192
+ fs::remove_file(&tmp).ok();
193
+ }
194
+
195
+ #[test]
196
+ fn test_mixed_comment_types() {
197
+ let content = "# REMIND_ME: { gem: 'a' }\n=begin\n REMIND_ME: { gem: 'b' }\n=end\n";
198
+ let tmp = std::env::temp_dir().join("test_mixed.rb");
199
+ fs::write(&tmp, content).unwrap();
200
+ let matches = scan_file(tmp.to_str().unwrap());
201
+ assert_eq!(matches.len(), 2);
202
+ assert!(matches[0].source_location.ends_with(":1:1")); // single-line
203
+ assert!(matches[1].source_location.ends_with(":2:1")); // block, points to =begin
204
+ fs::remove_file(&tmp).ok();
205
+ }
206
+ }
@@ -10,6 +10,13 @@ require_relative 'reminder/generator'
10
10
  require_relative 'utils/logger'
11
11
  require_relative 'utils/result_printer'
12
12
 
13
+ begin
14
+ require 'remind_me/remind_me_native'
15
+ REMIND_ME_NATIVE_AVAILABLE = true
16
+ rescue LoadError
17
+ REMIND_ME_NATIVE_AVAILABLE = false
18
+ end
19
+
13
20
  module RemindMe
14
21
  class Runner
15
22
  extend BailOut
@@ -33,6 +40,27 @@ module RemindMe
33
40
  end
34
41
 
35
42
  def self.collect_reminders(path)
43
+ if REMIND_ME_NATIVE_AVAILABLE
44
+ collect_reminders_native(path)
45
+ else
46
+ # :nocov:
47
+ collect_reminders_ruby(path)
48
+ # :nocov:
49
+ end
50
+ end
51
+
52
+ def self.collect_reminders_native(path)
53
+ raw_comments = RemindMe::Native.scan_for_remind_me_comments(path)
54
+ return if raw_comments.empty?
55
+
56
+ Parallel.flat_map(in_groups(raw_comments, processor_count, false)) do |comments|
57
+ parser = silent_parser
58
+ comments.flat_map { |raw_comment| RemindMe::Reminder::Generator.generate(raw_comment[0], raw_comment[1], parser) }
59
+ end
60
+ end
61
+
62
+ # :nocov:
63
+ def self.collect_reminders_ruby(path)
36
64
  files = relevant_ruby_files(path)
37
65
  return if files.empty?
38
66
 
@@ -42,6 +70,7 @@ module RemindMe
42
70
  raw_comments.flat_map { |raw_comment| RemindMe::Reminder::Generator.generate(raw_comment[0], raw_comment[1], parser) }
43
71
  end
44
72
  end
73
+ # :nocov:
45
74
 
46
75
  def self.silent_parser
47
76
  parser = Parser::CurrentRuby.new
@@ -65,6 +94,7 @@ module RemindMe
65
94
  .map { |x| [x[0], x[1][1].split("\n").first] }
66
95
  end
67
96
 
97
+ # :nocov:
68
98
  def self.relevant_ruby_files(parse_path)
69
99
  Parallel.flat_map(in_groups(collect_ruby_files(parse_path), processor_count, false)) do |files|
70
100
  files.select do |file|
@@ -84,6 +114,7 @@ module RemindMe
84
114
  end
85
115
  files
86
116
  end
117
+ # :nocov:
87
118
 
88
119
  def self.in_groups(array, number, fill_with = nil)
89
120
  division = array.size.div number
@@ -111,7 +142,9 @@ module RemindMe
111
142
 
112
143
  private_class_method :in_groups,
113
144
  :collect_ruby_files,
114
- :collect_relevant_comments
145
+ :collect_relevant_comments,
146
+ :collect_reminders_native,
147
+ :collect_reminders_ruby
115
148
  end
116
149
  end
117
150
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RemindMe
4
- VERSION = '0.6.0'
4
+ VERSION = '0.7.0'
5
5
  end
data/remind_me.gemspec CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
12
12
  spec.description = spec.summary
13
13
  spec.homepage = 'https://github.com/nikola-maric/remind_me'
14
14
  spec.license = 'MIT'
15
- spec.required_ruby_version = Gem::Requirement.new('>= 2.3.0')
15
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.7.0')
16
16
 
17
17
  spec.metadata['homepage_uri'] = spec.homepage
18
18
  spec.metadata['source_code_uri'] = spec.homepage
@@ -26,8 +26,11 @@ Gem::Specification.new do |spec|
26
26
  spec.bindir = 'exe'
27
27
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
28
28
  spec.require_paths = ['lib']
29
+ spec.extensions = ['ext/remind_me/extconf.rb']
29
30
 
30
31
  spec.add_development_dependency 'rake'
32
+ spec.add_development_dependency 'rake-compiler'
33
+ spec.add_development_dependency 'rb_sys'
31
34
  spec.add_development_dependency 'rspec'
32
35
  spec.add_development_dependency 'rubocop'
33
36
  spec.add_development_dependency 'simplecov'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: remind_me
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nikola Marić
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-05-30 00:00:00.000000000 Z
11
+ date: 2026-02-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -24,6 +24,34 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake-compiler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rb_sys
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
27
55
  - !ruby/object:Gem::Dependency
28
56
  name: rspec
29
57
  requirement: !ruby/object:Gem::Requirement
@@ -99,20 +127,28 @@ description: Processor of REMIND_ME comments in the code, reminding us to revisi
99
127
  email:
100
128
  - nkl.maric@gmail.net
101
129
  executables: []
102
- extensions: []
130
+ extensions:
131
+ - ext/remind_me/extconf.rb
103
132
  extra_rdoc_files: []
104
133
  files:
105
134
  - ".github/workflows/main.yml"
106
135
  - ".gitignore"
107
136
  - ".rspec"
108
137
  - ".rubocop.yml"
138
+ - CLAUDE.md
109
139
  - CODE_OF_CONDUCT.md
140
+ - Cargo.toml
110
141
  - Gemfile
111
142
  - LICENSE.txt
112
143
  - README.md
113
144
  - Rakefile
114
145
  - bin/console
115
146
  - bin/setup
147
+ - ext/remind_me/Cargo.toml
148
+ - ext/remind_me/extconf.rb
149
+ - ext/remind_me/src/bench.rs
150
+ - ext/remind_me/src/lib.rs
151
+ - ext/remind_me/src/scanner.rs
116
152
  - lib/remind_me.rb
117
153
  - lib/remind_me/bail_out.rb
118
154
  - lib/remind_me/railtie.rb
@@ -137,7 +173,7 @@ metadata:
137
173
  homepage_uri: https://github.com/nikola-maric/remind_me
138
174
  source_code_uri: https://github.com/nikola-maric/remind_me
139
175
  changelog_uri: https://github.com/nikola-maric/remind_me
140
- post_install_message:
176
+ post_install_message:
141
177
  rdoc_options: []
142
178
  require_paths:
143
179
  - lib
@@ -145,15 +181,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
145
181
  requirements:
146
182
  - - ">="
147
183
  - !ruby/object:Gem::Version
148
- version: 2.3.0
184
+ version: 2.7.0
149
185
  required_rubygems_version: !ruby/object:Gem::Requirement
150
186
  requirements:
151
187
  - - ">="
152
188
  - !ruby/object:Gem::Version
153
189
  version: '0'
154
190
  requirements: []
155
- rubygems_version: 3.1.4
156
- signing_key:
191
+ rubygems_version: 3.4.14
192
+ signing_key:
157
193
  specification_version: 4
158
194
  summary: Processor of REMIND_ME comments in the code, reminding us to revisit parts
159
195
  of code