Class: Vehicles::Model
- Inherits:
-
Object
- Object
- Vehicles::Model
- Defined in:
- lib/vehicles/model.rb,
sig/vehicles.rbs
Overview
A single vehicle nameplate, e.g. "Volkswagen Golf". A lightweight, immutable value object — no ActiveRecord, no mutation. Reads like English on purpose.
car = Vehicles.find("vw golf")
car.make # => "Volkswagen"
car.name # => "Golf"
car.full_name # => "Volkswagen Golf"
car.body_type # => :hatchback
car.suv? # => false
Constant Summary collapse
- KINDS =
Vehicle kinds (RDW
voertuigsoort). Today the bundled data is all :car; the shape already supports the rest for when those packs land. %i[car motorcycle van truck pickup trailer bus moped quad trike].freeze
- BODY_TYPES =
Body types — the sub-classification within a kind. For cars these are the familiar shapes; motorcycle styles (:naked, :adventure, …) reuse this field.
%i[ hatchback sedan wagon suv mpv coupe convertible roadster pickup van ].freeze
- REGIONS =
Continent codes (the model
regionsrollup). Order = rough market size. %i[eu na as sa oc af].freeze
Instance Attribute Summary collapse
-
#aliases ⇒ Object
readonly
Returns the value of attribute aliases.
-
#availability ⇒ Object
readonly
Returns the value of attribute availability.
-
#body_type ⇒ Symbol
readonly
Returns the value of attribute body_type.
-
#global_decile ⇒ Object
readonly
Returns the value of attribute global_decile.
-
#kind ⇒ Symbol
readonly
Returns the value of attribute kind.
-
#make ⇒ String
readonly
Returns the value of attribute make.
-
#make_slug ⇒ String
readonly
Returns the value of attribute make_slug.
-
#model_slug ⇒ String
readonly
The bare model slug ("golf"), used as the value in
model_options. -
#name ⇒ String
readonly
Returns the value of attribute name.
-
#regions ⇒ Object
readonly
Returns the value of attribute regions.
Instance Method Summary collapse
-
#==(other) ⇒ Object
(also: #eql?)
Value-object equality — two models with the same slug are equal.
-
#available_in?(country) ⇒ Boolean
Evidence of presence in a country (see
availabilityfor semantics): Vehicles.find("vw golf").available_in?(:nl) # => true. -
#available_in_region?(region) ⇒ Boolean
Evidence of presence on a continent (:eu/:na/:sa/:as/:oc/:af): Vehicles.find("perodua myvi").available_in_region?(:as) # => true.
-
#car? ⇒ Boolean
predicate sugar for each kind/body type: car?, suv?, hatchback?, coupe?, ...
- #common? ⇒ Boolean
-
#full_name ⇒ String
(also: #to_s)
"Volkswagen Golf" — the natural label for a model on its own.
- #hash ⇒ Object
- #hatchback? ⇒ Boolean
-
#image(year: nil, color: nil) ⇒ String?
Image URL, optionally year-/color-accurate.
-
#initialize(attrs, make:, make_slug:) ⇒ Model
constructor
A new instance of Model.
- #inspect ⇒ Object
-
#popular? ⇒ Boolean
Top-20% popularity across covered markets.
- #rare? ⇒ Boolean
-
#rarity ⇒ Object
Rarity tier from the popularity decile — the coarse "how much data do I want to show" knob.
-
#segment ⇒ Symbol?
Editorial market segment, e.g.
-
#slug ⇒ String
Composite, stable slug: "volkswagen-golf".
- #suv? ⇒ Boolean
- #to_h ⇒ Hash[Symbol, untyped]
-
#two_wheeler? ⇒ Boolean
Motorcycle OR moped — the union pickers usually want ("two-wheeler section" in an insurance/marketplace form).
-
#years ⇒ Range[Integer]?
Production years as a Range, e.g.
Constructor Details
#initialize(attrs, make:, make_slug:) ⇒ Model
Returns a new instance of Model.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/vehicles/model.rb', line 34 def initialize(attrs, make:, make_slug:) @make = make @make_slug = make_slug @name = attrs["name"] @model_slug = attrs["slug"] @kind = (attrs["kind"] || "car").to_sym # nil = no body vocabulary for this record yet (most non-car kinds). # A default would be a lie — predicates just return false instead. @body_type = attrs["body_type"]&.to_sym # Popularity decile 1 (most popular) … 10, averaged over every country # with registration counts. nil = catalog-only evidence, no counts yet. @global_decile = attrs["global_decile"] # ISO-3166-1 alpha-2 codes where an official source evidences the model. # Evidence of PRESENCE, not proof of official marketing (grey imports # count — they're real vehicles on real roads). @availability = (attrs["availability"] || []).freeze # Continent rollup of availability (:eu/:na/:sa/:as/:oc/:af). @regions = (attrs["regions"] || []).map(&:to_sym).freeze # Documented alternate names (nicknames, native scripts, market names). @aliases = (attrs["aliases"] || []).freeze freeze end |
Instance Attribute Details
#aliases ⇒ Object (readonly)
Returns the value of attribute aliases.
27 28 29 |
# File 'lib/vehicles/model.rb', line 27 def aliases @aliases end |
#availability ⇒ Object (readonly)
Returns the value of attribute availability.
27 28 29 |
# File 'lib/vehicles/model.rb', line 27 def availability @availability end |
#body_type ⇒ Symbol (readonly)
Returns the value of attribute body_type.
27 28 29 |
# File 'lib/vehicles/model.rb', line 27 def body_type @body_type end |
#global_decile ⇒ Object (readonly)
Returns the value of attribute global_decile.
27 28 29 |
# File 'lib/vehicles/model.rb', line 27 def global_decile @global_decile end |
#kind ⇒ Symbol (readonly)
Returns the value of attribute kind.
27 28 29 |
# File 'lib/vehicles/model.rb', line 27 def kind @kind end |
#make ⇒ String (readonly)
Returns the value of attribute make.
27 28 29 |
# File 'lib/vehicles/model.rb', line 27 def make @make end |
#make_slug ⇒ String (readonly)
Returns the value of attribute make_slug.
27 28 29 |
# File 'lib/vehicles/model.rb', line 27 def make_slug @make_slug end |
#model_slug ⇒ String (readonly)
The bare model slug ("golf"), used as the value in model_options.
69 70 71 |
# File 'lib/vehicles/model.rb', line 69 def model_slug @model_slug end |
#name ⇒ String (readonly)
Returns the value of attribute name.
27 28 29 |
# File 'lib/vehicles/model.rb', line 27 def name @name end |
#regions ⇒ Object (readonly)
Returns the value of attribute regions.
27 28 29 |
# File 'lib/vehicles/model.rb', line 27 def regions @regions end |
Instance Method Details
#==(other) ⇒ Object Also known as: eql?
Value-object equality — two models with the same slug are equal.
133 134 135 |
# File 'lib/vehicles/model.rb', line 133 def ==(other) other.is_a?(Model) && other.slug == slug end |
#available_in?(country) ⇒ Boolean
85 86 87 |
# File 'lib/vehicles/model.rb', line 85 def available_in?(country) availability.include?(country.to_s.downcase) end |
#available_in_region?(region) ⇒ Boolean
91 92 93 |
# File 'lib/vehicles/model.rb', line 91 def available_in_region?(region) regions.include?(region.to_sym) end |
#car? ⇒ Boolean
predicate sugar for each kind/body type: car?, suv?, hatchback?, coupe?, ...
87 |
# File 'sig/vehicles.rbs', line 87
def car?: () -> bool
|
#common? ⇒ Boolean
123 |
# File 'lib/vehicles/model.rb', line 123 def common? = rarity == :common |
#full_name ⇒ String Also known as: to_s
"Volkswagen Golf" — the natural label for a model on its own.
58 59 60 |
# File 'lib/vehicles/model.rb', line 58 def full_name "#{make} #{name}" end |
#hash ⇒ Object
138 139 140 |
# File 'lib/vehicles/model.rb', line 138 def hash slug.hash end |
#hatchback? ⇒ Boolean
89 |
# File 'sig/vehicles.rbs', line 89
def hatchback?: () -> bool
|
#image(year: nil, color: nil) ⇒ String?
Image URL, optionally year-/color-accurate. nil without hosted data.
163 164 165 |
# File 'lib/vehicles/model.rb', line 163 def image(year: nil, color: nil) Vehicles.resolve(:image, self, year: year, color: color) end |
#inspect ⇒ Object
142 143 144 |
# File 'lib/vehicles/model.rb', line 142 def inspect %(#<Vehicles::Model "#{full_name}" #{body_type || kind}>) end |
#popular? ⇒ Boolean
Top-20% popularity across covered markets. false when unranked (nil decile) — "we don't know" must never read as "popular".
104 105 106 |
# File 'lib/vehicles/model.rb', line 104 def popular? !global_decile.nil? && global_decile <= 2 end |
#rare? ⇒ Boolean
124 |
# File 'lib/vehicles/model.rb', line 124 def rare? = rarity == :rare |
#rarity ⇒ Object
Rarity tier from the popularity decile — the coarse "how much data do I want to show" knob. Deciles are the moat's measured signal; this buckets them into three names apps can filter on WITHOUT us exposing raw counts:
:common deciles 1-3 (the names everyone knows — safe default filter)
:average deciles 4-7
:rare deciles 8-10
:unknown unranked (catalog-only evidence — no popularity signal yet)
115 116 117 118 119 120 121 |
# File 'lib/vehicles/model.rb', line 115 def rarity return :unknown if global_decile.nil? return :common if global_decile <= 3 return :average if global_decile <= 7 :rare end |
#segment ⇒ Symbol?
Editorial market segment, e.g. :hot_hatch, :supercar. nil without hosted data.
158 159 160 |
# File 'lib/vehicles/model.rb', line 158 def segment Vehicles.resolve(:segment, self) end |
#slug ⇒ String
Composite, stable slug: "volkswagen-golf".
64 65 66 |
# File 'lib/vehicles/model.rb', line 64 def slug "#{make_slug}-#{@model_slug}" end |
#suv? ⇒ Boolean
88 |
# File 'sig/vehicles.rbs', line 88
def suv?: () -> bool
|
#to_h ⇒ Hash[Symbol, untyped]
126 127 128 129 130 |
# File 'lib/vehicles/model.rb', line 126 def to_h { make: make, model: name, slug: slug, kind: kind, body_type: body_type, global_decile: global_decile, rarity: rarity, availability: availability, regions: regions, aliases: aliases } end |
#two_wheeler? ⇒ Boolean
Motorcycle OR moped — the union pickers usually want ("two-wheeler section" in an insurance/marketplace form).
79 80 81 |
# File 'lib/vehicles/model.rb', line 79 def two_wheeler? %i[motorcycle moped].include?(@kind) end |