Skip to content

Commit

Permalink
Implement pluralization engine
Browse files Browse the repository at this point in the history
  • Loading branch information
virolea committed Oct 3, 2024
1 parent 7a2d9f2 commit 111d8fe
Show file tree
Hide file tree
Showing 21 changed files with 233 additions and 2 deletions.
1 change: 1 addition & 0 deletions app/models/rosetta/locale.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class Locale < ApplicationRecord

has_many :text_entries, dependent: :destroy
after_create_commit :notify_translated_models
has_many :pluralization_rules, dependent: :destroy

class << self
def available_locales
Expand Down
21 changes: 21 additions & 0 deletions app/models/rosetta/pluralization_rule.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
module Rosetta
class PluralizationRule < ApplicationRecord
OPERATORS = {
less_than_or_equal_to: Pluralization::Operators::LessThanOrEqualTo,
less_than: Pluralization::Operators::LessThan,
equal_to: Pluralization::Operators::EqualTo,
greater_than_or_equal_to: Pluralization::Operators::GreaterThanOrEqualTo,
greater_than: Pluralization::Operators::GreaterThan
}.with_indifferent_access

belongs_to :locale

validates :name, :operator, :threshold, presence: true
validates :threshold, numericality: { greater_than_or_equal_to: 0 }
validates :operator, inclusion: { in: OPERATORS.keys }

def activated?(test_value)
OPERATORS[operator].new(value: test_value, threshold: threshold).check
end
end
end
14 changes: 14 additions & 0 deletions db/migrate/20240920134441_create_rosetta_pluralization_rules.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class CreateRosettaPluralizationRules < ActiveRecord::Migration[6.1]
def change
create_table :rosetta_pluralization_rules do |t|
t.string :name
t.string :operator
t.integer :threshold
t.references :locale, null: false

t.timestamps

t.foreign_key :rosetta_locales, column: :locale_id
end
end
end
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class AddDefaultToRosettaLocales < ActiveRecord::Migration[7.2]
class AddDefaultToRosettaLocales < ActiveRecord::Migration[6.1]
def change
add_column :rosetta_locales, :default, :boolean, default: false
end
Expand Down
7 changes: 7 additions & 0 deletions lib/rosetta-rails.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@
require "rosetta/translated/create"
require "rosetta/translated/delete"

require "rosetta/pluralization/base_operator"
require "rosetta/pluralization/operators/less_than_or_equal_to"
require "rosetta/pluralization/operators/less_than"
require "rosetta/pluralization/operators/equal_to"
require "rosetta/pluralization/operators/greater_than_or_equal_to"
require "rosetta/pluralization/operators/greater_than"

module Rosetta
module Base
def locale
Expand Down
14 changes: 14 additions & 0 deletions lib/rosetta/pluralization/base_operator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module Rosetta
module Pluralization
class BaseOperator
def initialize(value:, threshold:)
@value = value
@threshold = threshold
end

def check
raise NotImplementedError
end
end
end
end
11 changes: 11 additions & 0 deletions lib/rosetta/pluralization/operators/equal_to.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module Rosetta
module Pluralization
module Operators
class EqualTo < BaseOperator
def check
@value == @threshold
end
end
end
end
end
11 changes: 11 additions & 0 deletions lib/rosetta/pluralization/operators/greater_than.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module Rosetta
module Pluralization
module Operators
class GreaterThan < BaseOperator
def check
@value > @threshold
end
end
end
end
end
11 changes: 11 additions & 0 deletions lib/rosetta/pluralization/operators/greater_than_or_equal_to.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module Rosetta
module Pluralization
module Operators
class GreaterThanOrEqualTo < BaseOperator
def check
@value >= @threshold
end
end
end
end
end
11 changes: 11 additions & 0 deletions lib/rosetta/pluralization/operators/less_than.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module Rosetta
module Pluralization
module Operators
class LessThan < BaseOperator
def check
@value < @threshold
end
end
end
end
end
11 changes: 11 additions & 0 deletions lib/rosetta/pluralization/operators/less_than_or_equal_to.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module Rosetta
module Pluralization
module Operators
class LessThanOrEqualTo < BaseOperator
def check
@value <= @threshold
end
end
end
end
end
13 changes: 12 additions & 1 deletion test/dummy/db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 2024_10_02_152043) do
ActiveRecord::Schema[7.2].define(version: 2024_10_02_152043) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"

Expand All @@ -24,6 +24,16 @@
t.index ["code"], name: "index_rosetta_locales_on_code", unique: true
end

create_table "rosetta_pluralization_rules", force: :cascade do |t|
t.string "name"
t.string "operator"
t.integer "threshold"
t.bigint "locale_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["locale_id"], name: "index_rosetta_pluralization_rules_on_locale_id"
end

create_table "rosetta_text_entries", force: :cascade do |t|
t.text "content", null: false
t.bigint "locale_id", null: false
Expand All @@ -46,6 +56,7 @@
t.index ["to_id"], name: "index_rosetta_translations_on_to_id"
end

add_foreign_key "rosetta_pluralization_rules", "rosetta_locales", column: "locale_id"
add_foreign_key "rosetta_text_entries", "rosetta_locales", column: "locale_id"
add_foreign_key "rosetta_translations", "rosetta_locales", column: "target_locale_id"
add_foreign_key "rosetta_translations", "rosetta_text_entries", column: "from_id"
Expand Down
7 changes: 7 additions & 0 deletions test/fixtures/rosetta/pluralization_rules.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html

french_less_than_or_equal_to_one:
name: Less than or equal to one
operator: less_than_or_equal_to
threshold: 1
locale: french
5 changes: 5 additions & 0 deletions test/helpers/pluralization_operator_helpers.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module PluralizationOperatorHelpers
def operator_class
self.class.name.gsub(/Test\z/, "").constantize
end
end
11 changes: 11 additions & 0 deletions test/lib/rosetta/pluralization/operators/equal_to_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
require "test_helper"

class Rosetta::Pluralization::Operators::EqualToTest < ActiveSupport::TestCase
include PluralizationOperatorHelpers

test "checks correct counts" do
assert operator_class.new(value: 1, threshold: 1).check
assert_not operator_class.new(value: 2, threshold: 1).check
assert_not operator_class.new(value: 0, threshold: 1).check
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
require "test_helper"

class Rosetta::Pluralization::Operators::GreaterThanOrEqualToTest < ActiveSupport::TestCase
include PluralizationOperatorHelpers

test "checks correct counts" do
assert operator_class.new(value: 1, threshold: 1).check
assert operator_class.new(value: 2, threshold: 1).check
assert_not operator_class.new(value: 0, threshold: 1).check
end
end
11 changes: 11 additions & 0 deletions test/lib/rosetta/pluralization/operators/greater_than_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
require "test_helper"

class Rosetta::Pluralization::Operators::GreaterThanTest < ActiveSupport::TestCase
include PluralizationOperatorHelpers

test "checks correct counts" do
assert operator_class.new(value: 2, threshold: 1).check
assert_not operator_class.new(value: 1, threshold: 1).check
assert_not operator_class.new(value: 0, threshold: 1).check
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
require "test_helper"

class Rosetta::Pluralization::Operators::LessThanOrEqualToTest < ActiveSupport::TestCase
include PluralizationOperatorHelpers

test "checks correct counts" do
assert operator_class.new(value: 2, threshold: 2).check
assert operator_class.new(value: 1, threshold: 2).check
assert_not operator_class.new(value: 5, threshold: 2).check
end
end
11 changes: 11 additions & 0 deletions test/lib/rosetta/pluralization/operators/less_than_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
require "test_helper"

class Rosetta::Pluralization::Operators::LessThanTest < ActiveSupport::TestCase
include PluralizationOperatorHelpers

test "checks correct counts" do
assert operator_class.new(value: 1, threshold: 2).check
assert_not operator_class.new(value: 2, threshold: 2).check
assert_not operator_class.new(value: 5, threshold: 2).check
end
end
39 changes: 39 additions & 0 deletions test/models/rosetta/pluralization_rule_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
require "test_helper"

module Rosetta
class PluralizationRuleTest < ActiveSupport::TestCase
setup do
@rule = rosetta_pluralization_rules(:french_less_than_or_equal_to_one)
end

test "valid" do
assert @rule.valid?
end

%i[name operator threshold].each do |attribute|
test "invalid without #{attribute}" do
@rule.public_send("#{attribute}=", nil)
assert_not @rule.valid?
assert_includes @rule.errors[attribute], "can't be blank"
end
end

test "operator must be included in the list" do
@rule.operator = "unknown_operator"
assert_not @rule.valid?
assert_includes @rule.errors[:operator], "is not included in the list"
end

test "value must be positive" do
@rule.threshold = -1
assert_not @rule.valid?
assert_includes @rule.errors[:threshold], "must be greater than or equal to 0"
end

test "#activated?" do
assert @rule.activated?(0)
assert @rule.activated?(1)
assert_not @rule.activated?(2)
end
end
end
2 changes: 2 additions & 0 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
ActiveRecord::Migrator.migrations_paths << File.expand_path("../db/migrate", __dir__)
require "rails/test_help"

require_relative "./helpers/pluralization_operator_helpers"

# Load fixtures from the engine
if ActiveSupport::TestCase.respond_to?(:fixture_paths=)
ActiveSupport::TestCase.fixture_paths = [ File.expand_path("fixtures", __dir__) ]
Expand Down

0 comments on commit 111d8fe

Please sign in to comment.