
Security News
New Website “Is It Really FOSS?” Tracks Transparency in Open Source Distribution Models
A new site reviews software projects to reveal if they’re truly FOSS, making complex licensing and distribution models easy to understand.
adaptiveconfiguration
Advanced tools
AdaptiveConfiguration is a powerful and flexible Ruby gem that allows you to define a DSL (Domain-Specific Language) for structured and hierarchical configurations. It is ideal for defining complex configurations for various use cases, such as API clients, application settings, or any scenario where structured configuration is needed.
In addition AdaptiveConfiguration can be more generally used to transform and validate JSON data from any source such as network request or API reponse.
Add this line to your application's Gemfile:
gem 'adaptiveconfiguration'
And then execute:
bundle install
Or install it yourself as:
gem install adaptiveconfiguration
To start using the adaptiveconfiguration
gem, simply require it in your Ruby application:
require 'adaptiveconfiguration'
AdaptiveConfiguration permits the caller to define a domain specific language +Builder+ specifying parameters, parameter collections, and related options. This builder can then be used to build or validate the configuration using the domain specific language.
Parameters are the basic building blocks of your configuration. They represent individual settings or options that you can define with specific types, defaults, and other attributes.
When defining a parameter, you specify its name and optionally type, default and alias.
require 'adaptiveconfiguration'
# define a configuration structure with parameters
configuration = AdaptiveConfiguration::Builder.new do
parameter :api_key, String
parameter :version, String, default: '1.0'
end
# build the configuration and set values
result = configuration.build! do
api_key 'your-api-key'
end
# access the configuration values
puts result[:api_key] # => "your-api-key"
puts result[:version] # => "1.0"
Notes:
parameter :api_key, String
defines a parameter named :api_key
with the type String
.parameter :version, String, default: '1.0'
defines a parameter with a default value.configuration.build!
creates a context where you can set values for the parameters.api_key 'your-api-key'
sets the value of :api_key
.result[:api_key]
retrieves the value of :api_key
.Groups allow you to organize related parameters into nested structures. This is useful for logically grouping settings and creating hierarchical configurations.
require 'adaptiveconfiguration'
configuration = AdaptiveConfiguration::Builder.new do
parameter :api_key, String
group :chat_options do
parameter :model, String, default: 'claude-3'
parameter :max_tokens, Integer, default: 1000
parameter :temperature, Float, default: 0.5
parameter :stream, TrueClass
end
end
result = configuration.build! do
api_key 'your-api-key'
chat_options do
temperature 0.8
stream true
end
end
# Accessing values
puts result[:api_key] # => "your-api-key"
puts result[:chat_options][:model] # => "claude-3"
puts result[:chat_options][:temperature] # => 0.8
puts result[:chat_options][:stream] # => true
Notes:
group :chat_options do ... end
defines a group named :chat_options
.chat_options do ... end
allows you to set parameters inside the :chat_options
group.result[:chat_options][:model]
.Array Parameters allow you to define parameters that can hold multiple values. This is useful when you need to collect lists of items, such as headers, tags, or multiple configuration entries.
require 'adaptiveconfiguration'
configuration = AdaptiveConfiguration::Builder.new do
parameter :api_key, String
group :request_options do
parameter :headers, String, array: true
end
end
result = configuration.build! do
api_key 'your-api-key'
request_options do
headers ['Content-Type: application/json', 'Authorization: Bearer token']
end
end
# Accessing array parameter
puts result[:request_options][:headers]
# => ["Content-Type: application/json", "Authorization: Bearer token"]
Notes:
parameter :headers, String, array: true
defines :headers
as an array parameter of type String
.headers
.:as
OptionThe :as
option allows you to map the parameter's name in your DSL to a different key in the
resulting configuration. This is useful when you need to conform to specific key names required
by APIs or other systems, while still using friendly method names in your configuration blocks.
require 'adaptiveconfiguration'
configuration = AdaptiveConfiguration::Builder.new do
parameter :api_key, String, as: :apiKey
group :user_settings, as: :userSettings do
parameter :user_name, String, as: :userName
end
end
result = configuration.build! do
api_key 'your-api-key'
user_settings do
user_name 'john_doe'
end
end
# Accessing values with mapped keys
puts result[:apiKey] # => "your-api-key"
puts result[:userSettings][:userName] # => "john_doe"
Notes:
:as
Option:
parameter :apiKey, String, as: :api_key
defines a parameter that you set using apiKey
,
but it's stored as :api_key
in the result.group :userSettings, as: :user_settings
maps the group name.apiKey
, userSettings
), but the values
are stored under the mapped keys.:api_key
, :user_settings
, :user_name
).The default
option allows you to specify a default value for a parameter. If you do not set
a value for that parameter during the build phase, it automatically uses the default.
require 'adaptiveconfiguration'
configuration = AdaptiveConfiguration::Builder.new do
parameter :api_key, String, default: 'default-api-key'
group :settings do
parameter :timeout, Integer, default: 30
parameter :retries, Integer, default: 3
end
end
result = configuration.build! do
# No need to set api_key or settings parameters unless you want to override defaults
end
# Accessing default values
puts result[:api_key] # => "default-api-key"
puts result[:settings][:timeout] # => 30
puts result[:settings][:retries] # => 3
Notes:
:api_key
have a default value specified with default: 'default-api-key'
.AdaptiveConfiguration automatically handles type conversion based on the parameter's specified
type. If you provide a value that can be converted to the specified type, it will do so.
If conversion fails, it raises a TypeError
.
require 'adaptiveconfiguration'
configuration = AdaptiveConfiguration::Builder.new do
parameter :max_tokens, Integer
parameter :temperature, Float
parameter :start_date, Date
end
result = configuration.build! do
max_tokens '1500' # String that can be converted to Integer
temperature '0.75' # String that can be converted to Float
start_date '2023-01-01' # String that can be converted to Date
end
# Accessing converted values
puts result[:max_tokens] # => 1500 (Integer)
puts result[:temperature] # => 0.75 (Float)
puts result[:start_date] # => #<Date: 2023-01-01 ...>
Notes:
'1500'
to 1500
(Integer).'0.75'
to 0.75
(Float).'2023-01-01'
to a Date
object.TypeError
.You can define custom converters for your own types, allowing you to extend the framework's capabilities.
require 'adaptiveconfiguration'
# define a custom class
class UpcaseString < String
def initialize( value )
super( value.to_s.upcase )
end
end
configuration = AdaptiveConfiguration::Builder.new do
convert( UpcaseString ) { | v | UpcaseString.new( v ) }
parameter :name, UpcaseString
end
result = configuration.build! do
name 'john doe'
end
# Accessing custom converted value
puts result[:name] # => "JOHN DOE"
puts result[:name].class # => UpcaseString
Notes:
convert( UpcaseString ) { | v | UpcaseString.new( v ) }
tells the builder how to convert
values to UpcaseString
.parameter :name, UpcaseString
defines a parameter of the custom type.name 'john doe'
, it converts it to 'JOHN DOE'
and stores it as an instance
of UpcaseString
.Certainly! Let's expand the first paragraph and complete the explanation in the section you added to the README.
AdaptiveConfiguration can also be utilized to transform and validate JSON data. By defining parameters and groups that mirror the expected structure of your JSON input, you can map and coerce incoming data into the desired format seamlessly.
The :as
option allows you to rename keys during this transformation process, ensuring that your data conforms to
specific API requirements or internal data models. Moreover, AdaptiveConfiguration provides built-in validation by
raising exceptions when the input data contains unexpected elements or elements of the wrong type, helping you
maintain data integrity and catch errors early in your data processing pipeline.
require 'adaptiveconfiguration'
# Define the expected structure of the JSON data
configuration = AdaptiveConfiguration::Builder.new do
parameter :api_key, String
group :user, as: :user_info do
parameter :name, String
parameter :email, String
parameter :age, Integer
end
group :preferences, as: :user_preferences do
parameter :notifications_enabled, TrueClass
parameter :theme, String, default: 'light'
end
end
# sample JSON data as a Hash (e.g., parsed from JSON/YAML or API response
input_data = {
'api_key' => 'your-api-key',
'user' => {
'name' => 'John Doe',
'email' => 'john@example.com',
'age' => '30' # age is a String that should be converted to Integer
},
'preferences' => {
'notifications_enabled' => 'true', # Should be converted to TrueClass
'theme' => 'dark'
},
'extra_field' => 'unexpected' # This field is not defined in the configuration
}
# build the configuration context using the input data
begin
result = configuration.build!( input_data )
# Access transformed and validated data
puts result[:api_key] # => "your-api-key"
puts result[:user_info][:name] # => "John Doe"
puts result[:user_info][:age] # => 30 (Integer)
puts result[:user_preferences][:theme] # => "dark"
rescue TypeError => e
puts "Validation Error: #{e.message}"
end
Explanation:
Defining the Structure:
parameter :api_key, String
defines the API key parameter.group :user, as: :user_info
defines a group for user data, which will be transformed to the key :user_info
in the result.:user
group, we define parameters for :name
, :email
, and :age
.group :preferences, as: :user_preferences
defines a group for user preferences, transformed to :user_preferences
.:as
Option:
:as
option renames the group keys in the resulting configuration, allowing the internal DSL names to differ from the output keys.Building the Configuration Context:
build!
:
build!
method to enforce strict validation. If any type coercion fails or if unexpected elements are present, it raises an exception.input_data
hash.api_key input_data['api_key']
sets the :api_key
parameter.user
and preferences
groups, we set the nested parameters accordingly.Type Conversion and Coercion:
'30'
(String) is converted to 30
(Integer) for the :age
parameter.'true'
(String) is converted to true
(TrueClass) for :notifications_enabled
.TypeError
is raised.'thirty'
were provided for :age
, it would raise a TypeError
because it cannot be converted to an Integer.Validation:
build!
method currently does not raise an exception for unexpected keys in the input data (like 'extra_field'
), but these keys are ignored.Transformation:
:as
option transforms the internal parameter and group names to match the desired output keys.Accessing Transformed Data:
result
object contains the transformed and validated data.result[:user_info][:name]
.Note:
build
method instead of build!
.build
method will attempt type coercion but will retain the original value if coercion fails, without raising an exception.By leveraging AdaptiveConfiguration in this way, you can create robust data transformation and validation pipelines that simplify handling complex JSON data structures, ensuring your application receives data that is correctly typed and structured.
Here's a comprehensive example that combines parameters, groups, array parameters, and defaults.
require 'adaptiveconfiguration'
configuration = AdaptiveConfiguration::Builder.new do
parameter :api_key, String
group :chat_options do
parameter :model, String, default: 'claude-3-5'
parameter :max_tokens, Integer, default: 2000
parameter :temperature, Float, default: 0.7
parameter :stream, TrueClass
parameter :stop_sequences, String, array: true
group :metadata do
parameter :user_id, String
parameter :session_id, String
end
end
group :message, as: :messages, array: true do
parameter :role, String
parameter :content, String
end
end
result = configuration.build! do
api_key 'your-api-key'
chat_options do
temperature 0.5
stop_sequences ['end', 'stop']
metadata do
user_id 'user-123'
session_id 'session-456'
end
end
message do
role 'system'
content 'You are a helpful assistant.'
end
message do
role 'user'
content 'Hello!'
end
end
# Accessing values
puts result[:api_key] # => "your-api-key"
puts result[:chat_options][:model] # => "claude-3-5"
puts result[:chat_options][:temperature] # => 0.5
puts result[:chat_options][:metadata][:user_id] # => "user-123"
puts result[:messages].map { | msg | msg[:content] }
# => ["You are a helpful assistant.", "Hello!"]
Notes:
:model
, :max_tokens
).:chat_options
, :metadata
).:stop_sequences
, :messages
).:as
option to map :message
to :messages
.:messages
array.Bug reports and pull requests are welcome on GitHub at https://github.com/EndlessInternational/adaptive-configuration.
The gem is available as open source under the terms of the MIT License.
FAQs
Unknown package
We found that adaptiveconfiguration demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
A new site reviews software projects to reveal if they’re truly FOSS, making complex licensing and distribution models easy to understand.
Security News
Astral unveils pyx, a Python-native package registry in beta, designed to speed installs, enhance security, and integrate deeply with uv.
Security News
The Latio podcast explores how static and runtime reachability help teams prioritize exploitable vulnerabilities and streamline AppSec workflows.