The project is in a healthy, maintained state
ImmosquareConstants gem provides a robust set of constants to facilitate application development across various domains
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies
 Project Readme
locale en
tags
app:immosquare-constants
audience:technique

immosquare-constants

ImmosquareConstants is a gem that provides a collection of constants useful for real estate applications, including a comprehensive list of global locales mapped to their native language names.

This page is written for the Ruby developers who use the gem. It covers the installation, the four modules it exposes — ImmosquareConstants::Ip for IP detection, ImmosquareConstants::Locale for native language names, ImmosquareConstants::Color for CSS color names and ImmosquareConstants::Regex for email patterns — and how the gem's own test suite, coverage report and CI pipeline are run. The only prerequisite is adding the gem to your Gemfile.

Installing the immosquare-constants gem

To install immosquare-constants, add this line to your Gemfile:

gem "immosquare-constants"

Then run:

bundle install

Detecting local, public and client IP addresses with ImmosquareConstants::Ip

The ImmosquareConstants::Ip module provides comprehensive IP address management with intelligent proxy handling and multiple output formats.

Get IP addresses. get_ips returns the local, public and client IP addresses of a request:

# Get local, public and client IP addresses
ips = ImmosquareConstants::Ip.get_ips(request)
puts "Local IP: #{ips.local}"
puts "Public IP: #{ips.public}"
puts "Client IP: #{ips.client}"

# Output example:
# Local IP: 192.168.1.100
# Public IP: 203.0.113.1
# Client IP: 10.0.0.1

Get the public IP address of the machine. get_my_ip_from_aws takes no request:

# Get the public IP address of the machine
ip = ImmosquareConstants::Ip.get_my_ip_from_aws
puts ip
# => 203.0.113.1

Get the front IP. get_front_ip resolves the request host through DNS to return the public IPv4 address that browsers actually reach (reverse proxy, CDN, load balancer) before traffic hits the application server. Useful when you need to know "from the outside, what IP does my domain point to?".

# Inside a controller / middleware
front_ip = ImmosquareConstants::Ip.get_front_ip(request)
puts front_ip
# => 203.0.113.1

Behavior of get_front_ip:

  • Uses explicit Google (8.8.8.8) and Cloudflare (1.1.1.1) nameservers with a 2s timeout per server, to avoid hangs when the system resolver is misconfigured.
  • Filters to IPv4 only, for consistency with the other IP helpers.
  • Returns nil if request is missing, the host is empty, or DNS resolution fails.

Multiple output formats. The get_ips method returns an IpResult object with various conversion methods:

ips = ImmosquareConstants::Ip.get_ips(request)

# JSON serialization
puts ips.to_json
# => {"local":"192.168.1.100","public":"203.0.113.1","client":"10.0.0.1"}

# Hash conversion (`to_h` is an alias of `to_hash`)
hash = ips.to_hash
# => {:local=>"192.168.1.100", :public=>"203.0.113.1", :client=>"10.0.0.1"}

# String representation
puts ips.to_s
# => local: 192.168.1.100, public: 203.0.113.1, client: 10.0.0.1

# Array conversion
array = ips.to_a
# => ["192.168.1.100", "203.0.113.1", "10.0.0.1"]

# Safe navigation
client_ip = ImmosquareConstants::Ip.get_ips(request)&.client
public_ip = ImmosquareConstants::Ip.get_ips(request)&.public

Intelligent proxy handling. The IP detection uses a smart hierarchy:

  1. HTTP_X_REAL_IP header (often set by load balancers/proxies)
  2. request.ip (Rails intelligent method)
  3. request.remote_ip (direct connection IP)

This ensures accurate client IP detection even behind proxies, load balancers, or CDNs.

Iterating over the IPs. IpResult iterates over key/value pairs, the keys being :local, :public and :client:

ips = ImmosquareConstants::Ip.get_ips(request)

# Iterate over key/value pairs
ips.each do |key, value|
  puts "#{key} => #{value}"
end
# :local => 192.168.1.100
# :public => 203.0.113.1
# :client => 10.0.0.1

# Iterate with an index
ips.each_with_index do |(key, value), index|
  puts "#{index}: #{key} => #{value}"
end
# 0: :local => 192.168.1.100
# 1: :public => 203.0.113.1
# 2: :client => 10.0.0.1

Looking up locale native names and CSS color hex values

ImmosquareConstants::Locale and ImmosquareConstants::Color are two lookup modules over the constants shipped with the gem: locale codes mapped to native language names, and CSS color names mapped to hexadecimal values.

To retrieve the native language name for a given locale:

locale_name = ImmosquareConstants::Locale.native_name_for_locale(:fr)
puts locale_name
# => Français

Ensure you pass the locale as either a string or a symbol. If the locale isn't present in the list, it will return nil.

To get only the base languages (without regional variants like :"fr-CA", :"en-US"):

languages = ImmosquareConstants::Locale.languages_with_native_names
puts languages[:fr]
# => Français
puts languages[:"fr-CA"]
# => nil (regional variants are filtered out)

To convert a color name to its hexadecimal value (case-insensitive):

color = ImmosquareConstants::Color.color_name_to_hex("red")
puts color
# => #ff0000

# Case variations work too
ImmosquareConstants::Color.color_name_to_hex("RED")     # => #ff0000
ImmosquareConstants::Color.color_name_to_hex("Red")     # => #ff0000
ImmosquareConstants::Color.color_name_to_hex(:red)      # => #ff0000

Matching and validating email addresses with ImmosquareConstants::Regex

ImmosquareConstants::Regex exposes three email patterns: email_raw, email and email_in_string.

email_raw defines the core email matching pattern used by both the email and email_in_string methods:

regex = ImmosquareConstants::Regex.email_raw
puts regex.source
# => [A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}
  • [A-Z0-9._%+-]+: Matches one or more allowed characters in the local part of the email (before the @), including letters, digits, and common special characters.

  • @: Matches the @ symbol separating the local part from the domain.

  • [A-Z0-9.-]+: Matches one or more allowed characters in the domain name, including letters, digits, dots, and hyphens.

  • \.: Matches a literal dot . separating the domain from the extension.

  • [A-Z]{2,}: Matches a domain extension consisting of at least two letters (e.g., com, org, net, fr).

The three patterns all carry the /i flag, so the upper-case character classes match lower-case addresses just as well. That flag is part of the Regexp object but not of regex.source, which is why it does not appear in the output printed above.

email matches a full email address:

email = "test@test.com"
valid = ImmosquareConstants::Regex.email.match?(email)
puts "Email: #{email} is valid? => #{valid}"
# => Email: test@test.com is valid? => true

To validate an email format using a regular expression:

validates_format_of :email, :with => ImmosquareConstants::Regex.email

email_in_string matches an email embedded in a string:

text   = "Contact us at test@test.com for more info or <test2@test2.fr>"
emails = text.scan(ImmosquareConstants::Regex.email_in_string)
puts emails.inspect
# => ["test@test.com", "test2@test2.fr"]

Running the immosquare-constants test suite with RSpec

This gem uses RSpec for testing. Make sure you have all dependencies installed:

bundle install

Run all tests:

bundle exec rspec

Run tests for a specific module:

# Test IP module only
bundle exec rspec spec/lib/immosquare-constants/ip_spec.rb

# Test Color module only
bundle exec rspec spec/lib/immosquare-constants/color_spec.rb

# Test Locale module only
bundle exec rspec spec/lib/immosquare-constants/locale_spec.rb

# Test Regex module only
bundle exec rspec spec/lib/immosquare-constants/regex_spec.rb

Run tests with more details:

# Show detailed output
bundle exec rspec --format documentation

# Show only failing tests
bundle exec rspec --format progress

# Run tests and stop on first failure
bundle exec rspec --fail-fast

Run the suite and the sample tasks through Rake:

# Run all tests via Rake
bundle exec rake spec

# Run sample tasks to test functionality
bundle exec rake immosquare_constants:sample:ip:get_ips
bundle exec rake immosquare_constants:sample:ip:get_my_ip_from_aws
bundle exec rake immosquare_constants:sample:color:color_name_to_hex
bundle exec rake immosquare_constants:sample:locale:native_name_for_locale
bundle exec rake immosquare_constants:sample:regex:email
bundle exec rake immosquare_constants:sample:regex:email_in_string
bundle exec rake immosquare_constants:sample:regex:email_raw

The test suite covers:

  • ✅ IP Module: Local, public and client IP detection, proxy handling, multiple output formats
  • ✅ Color Module: Color name to hex conversion with case-insensitive support
  • ✅ Locale Module: Native language name retrieval with nil fallback handling
  • ✅ Regex Module: Email validation patterns and string matching

Coverage report and continuous integration for immosquare-constants

Coverage of the immosquare-constants suite is measured by SimpleCov, and only when COVERAGE=true is exported — a plain bundle exec rspec stays fast and leaves no coverage/ directory behind.

COVERAGE=true bundle exec rspec

Two reports land in coverage/: index.html to read locally, and lcov.info for the CI. Branch coverage is enabled and spec/ is excluded from the measurement.

The CI builds the gem through bin/ci, its single entry point — the table below lists each command and what it performs on the build agent:

Command What it does
bin/ci init Installs the bundle, skipping the development group (editor and linter tooling)
bin/ci test Runs bundle exec rspec
bin/ci Both, in that order (the default, all)

bin/ci works the same on a laptop: it provisions no Ruby of its own, the runner selecting the ruby of .ruby-version and the gemset of .ruby-gemset before calling it. The script defaults COVERAGE to true, and the CI publishes coverage/lcov.info as its coverage report.

Anything the specs need therefore belongs to the test group of the Gemfile, never to development, which the CI does not install.

Contributing to immosquare-constants and license

Contributions are very much welcome! If you have enhancements, bug fixes, or other suggestions, please open an issue or submit a pull request on our GitHub repository.

This gem is licensed under the terms of the MIT License.