apacify 0.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c55a078f06803a6268b5df123a09667dba0a6ea7ab821f31578a79e0a4d10426
4
- data.tar.gz: c648ed8ae5233ee814da8c664c148ca207efabef7cfe9d8b9b4848d00b205e9a
3
+ metadata.gz: 1388346971f57a63a007b6e32798716f99dd1b5d2dcc1153624a495d7a6a0146
4
+ data.tar.gz: c58d4589773808ecb7d2af6c44322465ba1bab43f0704e9dbdbe6cb2e7fe6fa4
5
5
  SHA512:
6
- metadata.gz: 3b437c269f63a8b0a6c279765a12f2d36dd7c5307431e28baba9913c2d020cf9abbc8646971f722f9da78a9115069f03d95402b343cca7e37c913214ee06be63
7
- data.tar.gz: 7ec2fc67b96ad14d5f5d27eece0d42ae1e6e8db45217c64c5d9be8b5b03998f205fc6123ef64242de7957f571f8ca1135f0264a617c5a3d452364af8eeafb33b
6
+ metadata.gz: aea431081a8ce3ede8f03eb78b7d564f2f86f07cb86e4f695a1b1c14bc1bc44a1efbf91d00105a914dab5e7d31a3b9f0b91b0df5c0805a1978a9546821bcdd45
7
+ data.tar.gz: 3d4b59393c0b60b30ad0d308724fe8769cbfdfb39d3cb8c675ce3004b32419c71099f2891f69f89f2fb9d2b035ab9c41e142e9a090d8d16f31f36552add8dc0a
data/CHANGELOG.md CHANGED
@@ -1,4 +1,10 @@
1
- ## [Unreleased]
1
+ ## [0.3.0] - 2025-08-30
2
+
3
+ - Support Roman numerals
4
+
5
+ ## [0.2.0] - 2025-08-30
6
+
7
+ - Add ability to specify words to ignore during title case conversion
2
8
 
3
9
  ## [0.1.0] - 2025-07-26
4
10
 
data/README.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  A Ruby gem that converts strings to proper title case following APA (American Psychological Association) style guidelines. Apacify capitalizes strings while keeping minor words (articles, prepositions, conjunctions) lowercase, except when they appear at the beginning or end of the title, or after sentence-ending punctuation.
4
4
 
5
+ ## APA's Title Case Guide
6
+
7
+ 1. Capitalize the first word of the title/heading and of any subtitle/subheading;
8
+ 2. Capitalize all "major" words (nouns, verbs, adjectives, adverbs, and pronouns) in the title/heading, including the second part of hyphenated major words (e.g., Self-Report not Self-report); and
9
+ 3. Capitalize all words of four letters or more.
10
+
11
+ This boils down to using lowercase only for "minor" words of three letters or fewer, namely, for conjunctions (words like and, or, nor, and but), articles (the words a, an, and the), and prepositions (words like as, at, by, for, in, of, on, per, and to), as long as they aren't the first word in a title or subtitle. You can see examples of title case in our post on reference titles.
12
+
13
+ [Source](https://blog.apastyle.org/apastyle/2012/03/title-case-and-sentence-case-capitalization-in-apa-style.html)
14
+
5
15
  ## Installation
6
16
 
7
17
  Install the gem and add to the application's Gemfile by executing:
@@ -46,7 +56,21 @@ Hyphenated words are handled properly:
46
56
  # => "Mother-In-Law"
47
57
  ```
48
58
 
49
- ### Features
59
+ You can specify words to ignore during title case conversion. Ignored words will preserve their original case and bypass all capitalization rules:
60
+
61
+ ```ruby
62
+ "tokyo night (feat. evangeline)".apacify(ignore: "feat.")
63
+ # => "Tokyo Night (feat. Evangeline)"
64
+
65
+ "the quick brown fox".apacify(ignore: ["quick", "fox"])
66
+ # => "The quick Brown fox"
67
+
68
+ # Case-sensitive matching: "FEAT." != "feat."
69
+ "tokyo night (FEAT. evangeline)".apacify(ignore: "feat.")
70
+ # => "Tokyo Night (Feat. Evangeline)" # FEAT. not ignored, gets capitalized
71
+ ```
72
+
73
+ ## Features
50
74
 
51
75
  - Follows APA style title case rules
52
76
  - Capitalizes first and last words regardless of length
@@ -55,6 +79,7 @@ Hyphenated words are handled properly:
55
79
  - Handles hyphenated words correctly
56
80
  - Preserves original spacing and punctuation
57
81
  - Words 4 letters or longer are always capitalized
82
+ - Ignore specific words from capitalization rules
58
83
 
59
84
  ## Comparison with Rails' `#titleize`
60
85
 
@@ -2,15 +2,18 @@ require "yaml"
2
2
 
3
3
  module Apacify
4
4
  class Titleizer
5
- attr_reader :tokens
5
+ attr_reader :tokens, :ignore
6
6
 
7
- def initialize(string)
7
+ def initialize(string, ignore: [])
8
8
  @tokens = Tokenizer.new(string)
9
+ @ignore = wrap(ignore).reject(&:empty?)
9
10
  end
10
11
 
11
12
  def titleize
12
13
  tokens.map do |token|
13
- if should_capitalize?(token)
14
+ if token.in?(ignore)
15
+ token
16
+ elsif should_capitalize?(token)
14
17
  token.capitalize_word_parts
15
18
  else
16
19
  token
@@ -21,10 +24,47 @@ module Apacify
21
24
  private
22
25
 
23
26
  def should_capitalize?(token)
27
+ return false if ignored_word?(token)
28
+
24
29
  token.first? ||
25
30
  tokens.previous(token).sentence_ending_punctuation? ||
26
31
  !token.minor_word? ||
27
32
  token.long?
28
33
  end
34
+
35
+ def ignored_word?(token)
36
+ return false if ignore.empty?
37
+ return false if token.whitespace_or_punctuation?
38
+
39
+ token_string = token.string.strip
40
+
41
+ ignore.any? do |ignore_word|
42
+ # Case-sensitive direct match with full token string
43
+ if token_string == ignore_word
44
+ return true
45
+ end
46
+
47
+ # Check if ignore_word contains punctuation and token matches the word part (case-sensitive)
48
+ if ignore_word.match?(/[.!?:—()]/)
49
+ word_part = ignore_word.gsub(/[.!?:—()]+/, "")
50
+ if token_string == word_part
51
+ return true
52
+ end
53
+ end
54
+
55
+ false
56
+ end
57
+ end
58
+
59
+ def wrap(object)
60
+ case object
61
+ when nil
62
+ []
63
+ when Array
64
+ object.map(&:to_s)
65
+ else
66
+ [object]
67
+ end
68
+ end
29
69
  end
30
70
  end
data/lib/apacify/token.rb CHANGED
@@ -14,13 +14,25 @@ module Apacify
14
14
  end
15
15
 
16
16
  def capitalize_word_parts
17
- string.gsub(/(^|-)(\w)/) { |match| $1 + $2.upcase }
17
+ string.downcase.gsub(/(^|-)(\w+)/) do |match|
18
+ prefix = $1
19
+ word = $2
20
+ if roman_numeral?(word)
21
+ prefix + word.upcase
22
+ else
23
+ prefix + word.capitalize
24
+ end
25
+ end
18
26
  end
19
27
 
20
28
  def first?
21
29
  index == 0
22
30
  end
23
31
 
32
+ def in?(array)
33
+ array.include?(string)
34
+ end
35
+
24
36
  def letters
25
37
  string.downcase.gsub(/[^\w']/, "")
26
38
  end
@@ -44,5 +56,16 @@ module Apacify
44
56
  def whitespace_or_punctuation?
45
57
  string.match?(/\s+|[.!?:—()]+\s*/)
46
58
  end
59
+
60
+ private
61
+
62
+ def roman_numeral?(word)
63
+ # Only letters used in roman numerals
64
+ return false unless word.match?(/\A[ivxlcdm]+\z/)
65
+
66
+ # Roman numeral pattern - matches valid combinations
67
+ # This pattern handles: 1-3999 (I-MMMCMXCIX)
68
+ word.match?(/\A(?=[mdclxvi])m{0,4}(cm|cd|d?c{0,3})?(xc|xl|l?x{0,3})?(ix|iv|v?i{0,3})?\z/)
69
+ end
47
70
  end
48
71
  end
@@ -2,7 +2,7 @@ module Apacify
2
2
  class Tokenizer
3
3
  include Enumerable
4
4
 
5
- attr_reader :tokens
5
+ attr_reader :tokens, :ignore
6
6
 
7
7
  def initialize(string)
8
8
  @tokens = string
@@ -1,3 +1,3 @@
1
1
  module Apacify
2
- VERSION = "0.1.0"
2
+ VERSION = "0.3.0"
3
3
  end
data/lib/apacify.rb CHANGED
@@ -9,13 +9,13 @@ module Apacify
9
9
  File.join(__dir__, "..", "config", "minor.yml")
10
10
  ).freeze
11
11
 
12
- def self.titleize(string)
13
- Titleizer.new(string).titleize
12
+ def self.titleize(string, ignore: [])
13
+ Titleizer.new(string, ignore:).titleize
14
14
  end
15
15
  end
16
16
 
17
17
  class String
18
- def apacify
19
- Apacify.titleize(self)
18
+ def apacify(ignore: [])
19
+ Apacify.titleize(self, ignore:)
20
20
  end
21
21
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: apacify
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ariel Rzezak