orthotypo 0.4.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 733ea610f69c4a9ba891629fc085b5dc1aad322648f69ca081abc47c4a910f42
4
- data.tar.gz: 79ec3795341de0a320ab1b53d05fe94abd19056114212c2d3a0cae4123a6c927
3
+ metadata.gz: '05389ada5ba288061bd70f8e3170fb77b7d4d9df171b90e55d3c0c6edbf4d810'
4
+ data.tar.gz: edd5731b28644f5515133994a89185f2da4fc5cffb7c12273f2d1f48985571be
5
5
  SHA512:
6
- metadata.gz: 52594b2ea1bffb23aa7c099b0b2d80cd06bce233aa4614fa144085d2bb7e9b4011f86f3b22f080d1e0819167f211d79e8bc1047e2a9002b92b5f5be154df9e6a
7
- data.tar.gz: 932b85afbaa89f19ad041f3530a9a2d8a80fccf474e53197875f3fdcb845610cd2bb2c056f2727ec1d093845bcb151b74aa1f98ac874e8b8ce2ecb1a11ecf278
6
+ metadata.gz: 32280cc5abbc8b3d9a728db9943f815821c84c97384f59f6be2f0ba12789e2ef204a8c72ec579a2544cea505b9c2f3d46c51aef5db7006ac74e3e8d568813a85
7
+ data.tar.gz: b81b849cf147939f7ad2e6fb16ccbc3af8eed2016efa67a288fcc9fc2c7cbd3d9d2d4b78ad4d70588fd75dade26830e4443627024838404f01e4010cbb5f2989
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ .byebug_history
data/.rubocop.yml ADDED
@@ -0,0 +1,13 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.6
3
+
4
+ Style/StringLiterals:
5
+ Enabled: true
6
+ EnforcedStyle: double_quotes
7
+
8
+ Style/StringLiteralsInInterpolation:
9
+ Enabled: true
10
+ EnforcedStyle: double_quotes
11
+
12
+ Layout/LineLength:
13
+ Max: 120
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2023-10-12
4
+
5
+ - Initial release
@@ -0,0 +1,84 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
6
+
7
+ We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
8
+
9
+ ## Our Standards
10
+
11
+ Examples of behavior that contributes to a positive environment for our community include:
12
+
13
+ * Demonstrating empathy and kindness toward other people
14
+ * Being respectful of differing opinions, viewpoints, and experiences
15
+ * Giving and gracefully accepting constructive feedback
16
+ * Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
17
+ * Focusing on what is best not just for us as individuals, but for the overall community
18
+
19
+ Examples of unacceptable behavior include:
20
+
21
+ * The use of sexualized language or imagery, and sexual attention or
22
+ advances of any kind
23
+ * Trolling, insulting or derogatory comments, and personal or political attacks
24
+ * Public or private harassment
25
+ * Publishing others' private information, such as a physical or email
26
+ address, without their explicit permission
27
+ * Other conduct which could reasonably be considered inappropriate in a
28
+ professional setting
29
+
30
+ ## Enforcement Responsibilities
31
+
32
+ Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
33
+
34
+ Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
35
+
36
+ ## Scope
37
+
38
+ This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
39
+
40
+ ## Enforcement
41
+
42
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at contact@arnaudlevy.com. All complaints will be reviewed and investigated promptly and fairly.
43
+
44
+ All community leaders are obligated to respect the privacy and security of the reporter of any incident.
45
+
46
+ ## Enforcement Guidelines
47
+
48
+ Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:
49
+
50
+ ### 1. Correction
51
+
52
+ **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.
53
+
54
+ **Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.
55
+
56
+ ### 2. Warning
57
+
58
+ **Community Impact**: A violation through a single incident or series of actions.
59
+
60
+ **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.
61
+
62
+ ### 3. Temporary Ban
63
+
64
+ **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior.
65
+
66
+ **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.
67
+
68
+ ### 4. Permanent Ban
69
+
70
+ **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
71
+
72
+ **Consequence**: A permanent ban from any sort of public interaction within the community.
73
+
74
+ ## Attribution
75
+
76
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0,
77
+ available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
78
+
79
+ Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).
80
+
81
+ [homepage]: https://www.contributor-covenant.org
82
+
83
+ For answers to common questions about this code of conduct, see the FAQ at
84
+ https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations.
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in orthotypo.gemspec
6
+ gemspec
7
+
8
+ gem "rake", "~> 13.0"
9
+
10
+ gem "rubocop", "~> 1.21"
data/Gemfile.lock ADDED
@@ -0,0 +1,73 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ orthotypo (0.5.1)
5
+ htmlentities
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ ast (2.4.2)
11
+ base64 (0.1.1)
12
+ byebug (11.1.3)
13
+ diff-lcs (1.5.0)
14
+ htmlentities (4.3.4)
15
+ json (2.6.3)
16
+ language_server-protocol (3.17.0.3)
17
+ parallel (1.23.0)
18
+ parser (3.2.2.4)
19
+ ast (~> 2.4.1)
20
+ racc
21
+ racc (1.7.1)
22
+ rainbow (3.1.1)
23
+ rake (13.0.6)
24
+ regexp_parser (2.8.2)
25
+ rexml (3.2.6)
26
+ rspec (3.12.0)
27
+ rspec-core (~> 3.12.0)
28
+ rspec-expectations (~> 3.12.0)
29
+ rspec-mocks (~> 3.12.0)
30
+ rspec-core (3.12.2)
31
+ rspec-support (~> 3.12.0)
32
+ rspec-expectations (3.12.3)
33
+ diff-lcs (>= 1.2.0, < 2.0)
34
+ rspec-support (~> 3.12.0)
35
+ rspec-mocks (3.12.6)
36
+ diff-lcs (>= 1.2.0, < 2.0)
37
+ rspec-support (~> 3.12.0)
38
+ rspec-nc (0.3.0)
39
+ rspec (>= 3)
40
+ terminal-notifier (>= 1.4)
41
+ rspec-support (3.12.1)
42
+ rubocop (1.57.0)
43
+ base64 (~> 0.1.1)
44
+ json (~> 2.3)
45
+ language_server-protocol (>= 3.17.0)
46
+ parallel (~> 1.10)
47
+ parser (>= 3.2.2.4)
48
+ rainbow (>= 2.2.2, < 4.0)
49
+ regexp_parser (>= 1.8, < 3.0)
50
+ rexml (>= 3.2.5, < 4.0)
51
+ rubocop-ast (>= 1.28.1, < 2.0)
52
+ ruby-progressbar (~> 1.7)
53
+ unicode-display_width (>= 2.4.0, < 3.0)
54
+ rubocop-ast (1.29.0)
55
+ parser (>= 3.2.1.0)
56
+ ruby-progressbar (1.13.0)
57
+ terminal-notifier (2.0.0)
58
+ unicode-display_width (2.5.0)
59
+
60
+ PLATFORMS
61
+ arm64-darwin-22
62
+ x86_64-darwin-22
63
+
64
+ DEPENDENCIES
65
+ byebug
66
+ orthotypo!
67
+ rake (~> 13.0)
68
+ rspec
69
+ rspec-nc
70
+ rubocop (~> 1.21)
71
+
72
+ BUNDLED WITH
73
+ 2.4.6
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2023 noesya
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,57 @@
1
+ # Orthotypo
2
+
3
+ [![Maintainability](https://api.codeclimate.com/v1/badges/16eb1f100538684deee0/maintainability)](https://codeclimate.com/github/noesya/orthotypo/maintainability)
4
+
5
+ Il y a un corpus riche de règles typographiques, dépendant des langues.
6
+ Cette gem vise à intégrer ces règles et à automatiser leurs mises en application pour le web, quand cela est possible.
7
+
8
+ ## Installation
9
+
10
+ Install the gem and add to the application's Gemfile by executing:
11
+
12
+ $ bundle add orthotypo
13
+
14
+ If bundler is not being used to manage dependencies, install the gem by executing:
15
+
16
+ $ gem install orthotypo
17
+
18
+ ## Usage
19
+
20
+ Ajout d'espace fine insécable avant les signes doubles en français.
21
+
22
+ ```
23
+ "Un texte avec un signe double: mais il manque l'espace.".ortho
24
+ > Un texte avec un signe double : mais il manque l'espace.
25
+
26
+ ```
27
+
28
+ ## Roadmap
29
+
30
+ ### v1
31
+ 1. S'adapter aux locales (détecter I18n)
32
+ 2. Ne pas endommager l'HTML et les HTML entities (&nbsp;)
33
+
34
+ ### v2
35
+ Permettre les configs
36
+
37
+ ## Sources
38
+
39
+ - https://fr.wikipedia.org/wiki/Code_typographique
40
+ - http://www.orthotypographie.fr/
41
+ - https://www.scribbr.fr/elements-linguistiques/les-espaces/
42
+
43
+ ## Development
44
+
45
+ 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 the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
46
+
47
+ ## Contributing
48
+
49
+ Bug reports and pull requests are welcome on GitHub at https://github.com/noesya/orthotypo. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/orthotypo/blob/main/CODE_OF_CONDUCT.md).
50
+
51
+ ## License
52
+
53
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
54
+
55
+ ## Code of Conduct
56
+
57
+ Everyone interacting in the Orthotypo project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/orthotypo/blob/main/CODE_OF_CONDUCT.md).
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rspec/core/rake_task'
4
+ require 'bundler/gem_tasks'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "orthotypo"
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require "irb"
15
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,18 @@
1
+ module Orthotypo
2
+ class Composer::En < Composer
3
+
4
+ def chars_with_space_after
5
+ [
6
+ ',',
7
+ '.',
8
+ '...',
9
+ '…',
10
+ ';',
11
+ ':',
12
+ '!',
13
+ '?'
14
+ ]
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,5 @@
1
+ module Orthotypo
2
+ class Composer::EnGb < Composer::En
3
+
4
+ end
5
+ end
@@ -0,0 +1,57 @@
1
+ module Orthotypo
2
+ class Composer::Fr < Composer
3
+
4
+ protected
5
+
6
+ def chars_with_space_before
7
+ [
8
+ '%'
9
+ ]
10
+ end
11
+
12
+ def chars_with_space_after
13
+ [
14
+ ',',
15
+ '.',
16
+ '...',
17
+ '…'
18
+ ]
19
+ end
20
+
21
+ def chars_with_space_around
22
+ [
23
+ ';',
24
+ ':',
25
+ '!',
26
+ '?'
27
+ ]
28
+ end
29
+
30
+ def chars_with_no_space_around
31
+ [
32
+ "'",
33
+ '’',
34
+ 'ʼ'
35
+ ]
36
+ end
37
+
38
+ def pairs_with_space_around
39
+ [
40
+ '«»'
41
+ ]
42
+ end
43
+
44
+ def pairs_with_no_space_around
45
+ [
46
+ '“”',
47
+ '‘’',
48
+ '‹›',
49
+ '""',
50
+ "''",
51
+ "()",
52
+ "{}",
53
+ "[]"
54
+ ]
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,4 @@
1
+ module Orthotypo
2
+ class Composer::FrCh < Composer::Fr
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Orthotypo
2
+ class Composer::FrFr < Composer::Fr
3
+ end
4
+ end
@@ -0,0 +1,151 @@
1
+ module Orthotypo
2
+ class Composer
3
+ attr_reader :string, :ortho
4
+
5
+ SPACE = ' '.freeze
6
+ NBSP = ' '.freeze
7
+ NNBSP = ' '.freeze
8
+
9
+ def initialize(string, html: nil)
10
+ @string = string
11
+ @html = html
12
+ parse
13
+ end
14
+
15
+ protected
16
+
17
+ def chars_with_space_before
18
+ []
19
+ end
20
+
21
+ def chars_with_space_after
22
+ [
23
+ ',',
24
+ '.'
25
+ ]
26
+ end
27
+
28
+ def chars_with_space_around
29
+ []
30
+ end
31
+
32
+ def chars_with_no_space_around
33
+ []
34
+ end
35
+
36
+ def pairs_with_space_around
37
+ []
38
+ end
39
+
40
+ def pairs_with_no_space_around
41
+ []
42
+ end
43
+
44
+ def is_html?
45
+ # TODO contains tags?
46
+ @html || contains_html_entities?
47
+ end
48
+
49
+ def contains_html_entities?
50
+ @contains_html_entities ||= html_entities.decode(string) != string
51
+ end
52
+
53
+ def prepare_ortho
54
+ @ortho = string.dup
55
+ @ortho = html_entities.decode(@ortho) if contains_html_entities?
56
+ end
57
+
58
+ def clean_ortho
59
+ @ortho = html_entities.encode(@ortho) if contains_html_entities?
60
+ end
61
+
62
+ def parse
63
+ prepare_ortho
64
+ # Chars
65
+ parse_chars_with_space_before
66
+ parse_chars_with_space_after
67
+ parse_chars_with_space_around
68
+ parse_chars_with_no_space_around
69
+ # Pairs
70
+ parse_pairs_with_space_around
71
+ parse_pairs_with_no_space_around
72
+ # Numbers
73
+ parse_numbers
74
+ #
75
+ clean_ortho
76
+ end
77
+
78
+ def parse_chars_with_space_before
79
+ chars_with_space_before.each do |char|
80
+ # Espace normal avant -> espace fine insécable avant
81
+ fix(SPACE + '%', NNBSP + '%')
82
+ # Pas d'espace avant -> espace fine insécable avant
83
+ fix(/([[:alnum:]])%/, "\\1" + NNBSP + '%')
84
+ end
85
+ end
86
+
87
+ def parse_chars_with_space_after
88
+ chars_with_space_after.each do |char|
89
+ # Espace avant -> pas d'espace avant
90
+ fix(SPACE + char, char)
91
+ # Pas d'espace après -> espace après
92
+ fix(/[#{char}]([[:alnum:]])/, char + SPACE + "\\1")
93
+ end
94
+ end
95
+
96
+ def parse_chars_with_space_around
97
+ chars_with_space_around.each do |char|
98
+ # Espace normal avant -> espace fine insécable avant
99
+ fix(SPACE + char, NNBSP + char)
100
+ # Pas d'espace avant -> espace fine insécable avant
101
+ fix(/([[:alnum:]])[#{char}]/, "\\1" + NNBSP + char)
102
+ end
103
+ end
104
+
105
+ def parse_chars_with_no_space_around
106
+ chars_with_no_space_around.each do |char|
107
+ # Espace avant -> pas d'espace avant
108
+ fix(SPACE + char, char)
109
+ # Espace après -> pas d'espace après
110
+ fix(char + SPACE, char)
111
+ end
112
+ end
113
+
114
+ def parse_pairs_with_space_around
115
+ pairs_with_space_around.each do |marks|
116
+ opening = marks.chars.first
117
+ closing = marks.chars.last
118
+ # Espace normal -> espace fine insécable
119
+ fix(opening + SPACE, opening + NNBSP)
120
+ fix(SPACE + closing, NNBSP + closing)
121
+ # Pas d'espace -> espace fine insécable
122
+ fix(/[#{opening}]([^[:space:]])/, opening + NNBSP + "\\1")
123
+ fix(/([^[:space:]])[#{closing}]/, "\\1" + NNBSP + closing)
124
+ end
125
+ end
126
+
127
+ def parse_pairs_with_no_space_around
128
+ pairs_with_no_space_around.each do |marks|
129
+ opening = marks.chars.first
130
+ closing = marks.chars.last
131
+ # Espace -> pas d'espace
132
+ fix(opening + SPACE, opening)
133
+ fix(SPACE + closing, closing)
134
+ end
135
+ end
136
+
137
+ def parse_numbers
138
+ ['.', ','].each do |char|
139
+ fix(/([[:digit:]])[#{char}][[:space:]]([[:digit:]])/, "\\1" + char + "\\2")
140
+ end
141
+ end
142
+
143
+ def html_entities
144
+ @html_entities ||= HTMLEntities.new(:expanded)
145
+ end
146
+
147
+ def fix(bad, good)
148
+ @ortho.gsub! bad, good
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,5 @@
1
+ String.class_eval do
2
+ def ortho(locale: nil, html: nil)
3
+ @ortho ||= Orthotypo::Localizer.new(self, locale: locale, html: html).composer.ortho
4
+ end
5
+ end
@@ -0,0 +1,32 @@
1
+ module Orthotypo
2
+ class Localizer
3
+
4
+ DEFAULT_LOCALE = 'fr'
5
+
6
+ def initialize(string, locale: nil, html: nil)
7
+ @string = string
8
+ @locale = locale
9
+ @html = html
10
+ end
11
+
12
+ def composer
13
+ composer_class.new @string, html: @html
14
+ end
15
+
16
+ protected
17
+
18
+ def composer_class
19
+ composer_class = composer_class_for(@locale) unless @locale.nil?
20
+ composer_class ||= composer_class_for(DEFAULT_LOCALE)
21
+ composer_class
22
+ end
23
+
24
+ def composer_class_for(locale)
25
+ formatted_locale = locale.split('-').map(&:capitalize).join
26
+ class_name = "::Orthotypo::Composer::#{formatted_locale}"
27
+ Object.module_eval(class_name, __FILE__, __LINE__)
28
+ rescue
29
+ nil
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Orthotypo
4
+ VERSION = "0.5.1"
5
+ end
data/lib/orthotypo.rb ADDED
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "htmlentities"
4
+ require_relative "orthotypo/composer"
5
+ require_relative "orthotypo/composer/fr"
6
+ require_relative "orthotypo/composer/fr_fr"
7
+ require_relative "orthotypo/composer/fr_ch"
8
+ require_relative "orthotypo/composer/en"
9
+ require_relative "orthotypo/composer/en_gb"
10
+ require_relative "orthotypo/core_ext"
11
+ require_relative "orthotypo/localizer"
12
+ require_relative "orthotypo/version"
13
+
14
+ module Orthotypo
15
+ class Error < StandardError; end
16
+ end
data/orthotypo.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/orthotypo/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "orthotypo"
7
+ spec.version = Orthotypo::VERSION
8
+ spec.authors = ["Arnaud Levy"]
9
+ spec.email = ["arnaud.levy@noesya.coop"]
10
+
11
+ spec.summary = "Pour un texte correctement typographié"
12
+ spec.description = "Il y a un corpus riche de règles typographiques, dépendant des langues. Cette gem vise à intégrer ces règles et à automatiser leur mise en application pour le web, quand cela est possible."
13
+ spec.homepage = "https://github.com/noesya/orthotypo"
14
+ spec.license = "MIT"
15
+ spec.required_ruby_version = ">= 2.6.0"
16
+
17
+ spec.metadata["homepage_uri"] = spec.homepage
18
+ spec.metadata["source_code_uri"] = "https://github.com/noesya/orthotypo"
19
+
20
+ spec.files = `git ls-files`.split("\n")
21
+ spec.require_paths = "lib"
22
+
23
+ spec.add_dependency "htmlentities"
24
+
25
+ spec.add_development_dependency "rspec"
26
+ spec.add_development_dependency "rspec-nc"
27
+ spec.add_development_dependency "byebug"
28
+ end
data/sig/orthotypo.rbs ADDED
@@ -0,0 +1,4 @@
1
+ module Orthotypo
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
@@ -0,0 +1,17 @@
1
+
2
+ require 'spec_helper'
3
+
4
+ describe Orthotypo::Composer::En do
5
+ it 'removes spaces before double punctuation marks' do
6
+ expect("mot: suite".ortho(locale: 'en')).to eq "mot: suite"
7
+ expect("mot : suite".ortho(locale: 'en')).to eq "mot: suite"
8
+ expect("é: suite".ortho(locale: 'en')).to eq "é: suite"
9
+ expect("é : suite".ortho(locale: 'en')).to eq "é: suite"
10
+ expect("1: suite".ortho(locale: 'en')).to eq "1: suite"
11
+ expect("1 : suite".ortho(locale: 'en')).to eq "1: suite"
12
+ expect("mot; suite".ortho(locale: 'en')).to eq "mot; suite"
13
+ expect("mot ; suite".ortho(locale: 'en')).to eq "mot; suite"
14
+ expect("mot!".ortho(locale: 'en')).to eq "mot!"
15
+ expect("mot !".ortho(locale: 'en')).to eq "mot!"
16
+ end
17
+ end
@@ -0,0 +1,62 @@
1
+
2
+ require 'spec_helper'
3
+
4
+ describe Orthotypo::Composer::Fr do
5
+ it 'adds spaces before double punctuation marks' do
6
+ expect("mot: suite".ortho).to(eq("mot : suite"))
7
+ expect("é: suite".ortho).to(eq("é : suite"))
8
+ expect("1: suite".ortho).to(eq("1 : suite"))
9
+ expect("mot; suite".ortho).to(eq("mot ; suite"))
10
+ expect("mot!".ortho).to(eq("mot !"))
11
+ expect("mot !".ortho).to(eq("mot !"))
12
+ end
13
+
14
+ it 'transforms regular spaces before double punctuation marks' do
15
+ expect("mot : suite".ortho).to(eq("mot : suite"))
16
+ expect("é : suite".ortho).to(eq("é : suite"))
17
+ expect("1 : suite".ortho).to(eq("1 : suite"))
18
+ end
19
+
20
+ it 'fixes space before simple punctuation' do
21
+ expect("mot , suite".ortho).to(eq("mot, suite"))
22
+ expect("mot . suite".ortho).to(eq("mot. suite"))
23
+ expect("l 'approche".ortho).to(eq("l'approche"))
24
+ expect("l' approche".ortho).to(eq("l'approche"))
25
+ end
26
+
27
+ it 'fixes space after simple punctuation' do
28
+ expect("mot,suite".ortho).to(eq("mot, suite"))
29
+ expect("4,5".ortho).to(eq("4,5"))
30
+ end
31
+
32
+ it 'fixes quotation marks' do
33
+ expect("«mot»".ortho).to(eq("« mot »"))
34
+ expect("« mot »".ortho).to(eq("« mot »"))
35
+ expect("“ mot ”".ortho).to(eq("“mot”"))
36
+ expect("‘ mot ’".ortho).to(eq("‘mot’"))
37
+ expect("‹ mot ›".ortho).to(eq("‹mot›"))
38
+ expect("\" mot \"".ortho).to(eq("\"mot\""))
39
+ expect("' mot '".ortho).to(eq("'mot'"))
40
+ end
41
+
42
+ it 'fixes percent' do
43
+ expect("10%".ortho).to(eq("10 %"))
44
+ expect("10 %".ortho).to(eq("10 %"))
45
+ end
46
+
47
+ # https://www.scribbr.fr/elements-linguistiques/les-espaces/
48
+ it 'tests de Justine Debret' do
49
+ expect("Elle a vu son cousin,sa tante et son oncle.Ils allaient tous très bien.".ortho).to(eq("Elle a vu son cousin, sa tante et son oncle. Ils allaient tous très bien."))
50
+ expect("Elle dit: qui voudrait bien venir voir ce film? Il répond: moi; à moins qu’il ne fasse très beau!".ortho).to(eq("Elle dit : qui voudrait bien venir voir ce film ? Il répond : moi ; à moins qu’il ne fasse très beau !"))
51
+ expect("L’ hiver ne va pas durer toute l’année.".ortho).to(eq("L’hiver ne va pas durer toute l’année."))
52
+ expect("Elle ne disait plus rien…jusqu’au moment du repas.".ortho).to(eq("Elle ne disait plus rien… jusqu’au moment du repas."))
53
+ expect("Il a dit : «J’arrive ce matin ( ou plus tard ) à Paris [ rue de la République ] pour son anniversaire.»".ortho).to(eq("Il a dit : « J’arrive ce matin (ou plus tard) à Paris [rue de la République] pour son anniversaire. »"))
54
+ # Le test suivant n'est pas automatisable, parce qu'on ne peut distinguer un Paris-Brest (le gâteau) d'un Paris - Brest (le trajet)
55
+ # expect("Nous l’avons rencontré à Saint - Martin.".ortho).to(eq("Nous l’avons rencontré à Saint-Martin."))
56
+ # Le test suivant est-il automatisable ?
57
+ # expect("Il roule pendant 31, 5km.".ortho).to(eq("Il roule pendant 31,5 km."))
58
+ # Pas automatisable, rien ne permet de distinguer s'il s'agit d'un rang ou d'un nombre
59
+ # expect("Il en compte 1,000, 10,000, 36,742, 500,000, puis 1,000,000, 25,000,000, etc.".ortho).to(eq("Il en compte 1 000, 10 000, 36 742, 500 000, puis 1 000 000, 25 000 000, etc."))
60
+ # expect("Le numéro gagnant est le 3 541 672.".ortho).to(eq("Le numéro gagnant est le 3541672."))
61
+ end
62
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe Orthotypo do
4
+ it 'selects proper locale' do
5
+ expect(Orthotypo::Localizer.new('').composer).to be_a Orthotypo::Composer::Fr
6
+ expect(Orthotypo::Localizer.new('', locale: 'fr').composer).to be_a Orthotypo::Composer::Fr
7
+ expect(Orthotypo::Localizer.new('', locale: 'fr-FR').composer).to be_a Orthotypo::Composer::FrFr
8
+ expect(Orthotypo::Localizer.new('', locale: 'fr-CH').composer).to be_a Orthotypo::Composer::FrCh
9
+ expect(Orthotypo::Localizer.new('', locale: 'en').composer).to be_a Orthotypo::Composer::En
10
+ expect(Orthotypo::Localizer.new('', locale: 'en-GB').composer).to be_a Orthotypo::Composer::EnGb
11
+ expect(Orthotypo::Localizer.new('', locale: 'en-UNKNOWN').composer).to be_a Orthotypo::Composer::Fr
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe Orthotypo do
4
+ it 'leaves html entities untouched' do
5
+ expect("test &amp; test".ortho).to eq "test &amp; test"
6
+ end
7
+
8
+ it 'leaves html tags untouched' do
9
+ expect("<b>bold</b>".ortho).to eq "<b>bold</b>"
10
+ end
11
+ end
@@ -0,0 +1,2 @@
1
+ require 'byebug'
2
+ require 'Orthotypo'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: orthotypo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Arnaud Levy
@@ -74,7 +74,35 @@ email:
74
74
  executables: []
75
75
  extensions: []
76
76
  extra_rdoc_files: []
77
- files: []
77
+ files:
78
+ - ".gitignore"
79
+ - ".rubocop.yml"
80
+ - CHANGELOG.md
81
+ - CODE_OF_CONDUCT.md
82
+ - Gemfile
83
+ - Gemfile.lock
84
+ - LICENSE.txt
85
+ - README.md
86
+ - Rakefile
87
+ - bin/console
88
+ - bin/setup
89
+ - lib/orthotypo.rb
90
+ - lib/orthotypo/composer.rb
91
+ - lib/orthotypo/composer/en.rb
92
+ - lib/orthotypo/composer/en_gb.rb
93
+ - lib/orthotypo/composer/fr.rb
94
+ - lib/orthotypo/composer/fr_ch.rb
95
+ - lib/orthotypo/composer/fr_fr.rb
96
+ - lib/orthotypo/core_ext.rb
97
+ - lib/orthotypo/localizer.rb
98
+ - lib/orthotypo/version.rb
99
+ - orthotypo.gemspec
100
+ - sig/orthotypo.rbs
101
+ - spec/composer/en_spec.rb
102
+ - spec/composer/fr_spec.rb
103
+ - spec/localizer_spec.rb
104
+ - spec/orthotypo_spec.rb
105
+ - spec/spec_helper.rb
78
106
  homepage: https://github.com/noesya/orthotypo
79
107
  licenses:
80
108
  - MIT