mdub / config_mapper Goto Github PK
View Code? Open in Web Editor NEWMaps config data onto plain old Ruby objects
License: MIT License
Maps config data onto plain old Ruby objects
License: MIT License
Right now they're output as TrueClass | FalseClass
, which is very not user-friendly. They should be output as Boolean
or something along those lines.
We would like a way to define lists. In my head, the config would look like this:
people:
-
name: danial pearce
awesomeness: 10
preferences:
drink: beer
food: burgers
-
name: fred
awesomeness: 2
preferences:
drink: water
And the model might look something like this:
class Config < ConfigMapper::ConfigStruct
component_list :people do
attribute :name, String
attribute :awesomeness, Integer, default: 0
component_dict :preferences do
attribute :drink, String
attribute :food, String, default: "parmas"
end
end
end
Which would map to PORs like so:
{
"people": [
{ "name": "danial pearce", "awesomeness": 10, "preferences": { "drink": "beer", "food": "burgers" } },
{ "name": "fred", "awesomeness": 2, "preferences": { "drink": "wine", "food": "parmas" } },
]
}
I think doing the above is currently possible by creating a Types::People
, and using component :people, type: Types::People
although I've not yet tried. I think the above would be a nicer solution in the long run, as the entire config definition would be in 1 place instead of spread out across multiple types, where the "type" also has other stuff mingled in with it and doesn't read quite as nice as a simple config definition.
We're currently using ConfigMapper::ConfigStruct classes for defining our configuration data structure, and also maintain a separate 'configuration reference' yaml document for our users.
E.g. for the following code:
class State < ConfigMapper::ConfigStruct
component :position do
attribute :x, default: 0
attribute :y, default: 0
end
end
We would also write a companion config-reference.yml
document containing:
position:
type: Object
description: |
The position of our object
position.x:
type: Integer
description: |
x-coordinate
position.y:
type: Integer
description: |
y-coordinate
It would be great if ConfigStruct
elements (attributes, components and component_dicts) supported some additional documentation options, so that a config reference document could be generated.
I'm thinking this would involve adding description
option to all elements and a type
option for attributes, e.g.
component :position, description: "The position of our object" do
attribute :x, default: 0, description: "x-coordinate", type: Integer
attribute :y, default: 0, description: "y-coordinate", type: Integer
end
Then exposing a method on ConfigStruct
objects (maybe #reference_yaml
?) that would return a yaml object of the config-reference
data above.
Happy to make a PR but would like some feedback first :)
Hi @mdub,
Hope you are going well! Cheers for the work you have put into maintaining this gem.
Was inspired to use it after your chat at REA Ruby guild.
Only thing is I am having trouble running the example in the README for mapping nested config.
require 'config_mapper'
require 'config_mapper/config_struct'
class Position < ConfigMapper::ConfigStruct
attr_reader :x
attr_reader :y
def x=(arg); @x = Integer(arg); end
def y=(arg); @y = Integer(arg); end
end
positions = Hash.new { |h,k| h[k] = Position.new }
config_data = {
"fred" => { "x" => 2, "y" => 4 },
"mary" => { "x" => 3, "y" => 5 }
}
ConfigMapper.configure_with(config_data, positions)
puts positions["fred"].x #undefined method `x' for {"x"=>2, "y"=>4}:Hash (NoMethodError)
puts positions["mary"].y
If I use version 1.2 I can get it to work, so seems like this changed from version 1.2 to 1.3
These are the two release commits
git diff 007d777a1e44926337db41179770ed96c68e47f4 18fb8aa381ec54909404aa98aee258e51e4d76a1
Seems like the noteable change was from using dict_mapper
to collection_mapper
for hashs.
Unsure if nested config was purposely removed or if this is a bug.
In a situation of nested components, it would be handy for child nodes to know about their parents.
component_dict :teams do
attribute :name
component_dict :services do
attribute :name
def full_name
"#{_parent.name} - #{service.name}"
end
end
end
At the moment, I think within the context of a service
here, you don't have any access to the parent object. So something like this is not possible.
I'm not entire sure what options are available for implementing this, but happy to have a crack if you can give some guidance. Or just tell me it's a really bad idea ๐
Given a simple target object
class Position
attr_reader :x
attr_reader :y
def x=(arg)
@x = Integer(arg)
end
def y=(arg)
@y = Integer(arg)
end
end
pos = Position.new
configuration from a Hash is fine:
ConfigMapper.configure_with({"x" => 1}, pos)
pos #=> #<Position:0x007fc3bf8a55e0 @x=1>
but passing an array throws a TypeError
ConfigMapper.configure_with(["x"], pos)
TypeError: 0 is not a symbol nor a string
from ...
We should catch the exception, and return a helpful error message.
It'd be super cool if I could just set deprecated: true
on an attribute/component.
Or alternatively set it to a "deprecation_message" rather than just a boolean.
But it'd be nice if you could do this at a component level, as well as individual attributes.
One would have to ask for these deprecations manually, after the config was loaded. E.g. config.deprecations.each{|key, message| logger.warn("DEPRECATED: #{key} - #{message}") }
Since the config struct itself has no concept of a logger, or what might happen with deprecations, it simply needs the ability to mark a particular thing as deprecated, and a means to access all that info.
Let me know if you'd be interested in something like this at the global layer, otherwise I'll hack something for our specific needs.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.