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 +4 -4
- data/CHANGELOG.md +7 -1
- data/README.md +26 -1
- data/lib/apacify/titleizer.rb +43 -3
- data/lib/apacify/token.rb +24 -1
- data/lib/apacify/tokenizer.rb +1 -1
- data/lib/apacify/version.rb +1 -1
- data/lib/apacify.rb +4 -4
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1388346971f57a63a007b6e32798716f99dd1b5d2dcc1153624a495d7a6a0146
|
|
4
|
+
data.tar.gz: c58d4589773808ecb7d2af6c44322465ba1bab43f0704e9dbdbe6cb2e7fe6fa4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: aea431081a8ce3ede8f03eb78b7d564f2f86f07cb86e4f695a1b1c14bc1bc44a1efbf91d00105a914dab5e7d31a3b9f0b91b0df5c0805a1978a9546821bcdd45
|
|
7
|
+
data.tar.gz: 3d4b59393c0b60b30ad0d308724fe8769cbfdfb39d3cb8c675ce3004b32419c71099f2891f69f89f2fb9d2b035ab9c41e142e9a090d8d16f31f36552add8dc0a
|
data/CHANGELOG.md
CHANGED
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
|
-
|
|
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
|
|
data/lib/apacify/titleizer.rb
CHANGED
|
@@ -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
|
|
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)/)
|
|
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
|
data/lib/apacify/tokenizer.rb
CHANGED
data/lib/apacify/version.rb
CHANGED
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
|