russross / gcfg

Automatically exported from code.google.com/p/gcfg
Other
0 stars 0 forks source link

support for "array of section" #10

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
i have a config layout that repeats like

[item]
name=foo
active=true
sleep=12

[item]
name=bar
active=false
sleep=49

so the struct layout i want is 
[]Item {
name string
active bool
sleep int
}

but currently it wants 
Item {
[]name string
[]active bool
[]sleep int
}

reason i want first layout is that way if the config say forgets a line then 
the ordering could be broken if you
are expecting each item to be grouped

error with first is complaining about using a map or a struct so layout i want 
at least with current error checking doesn't work

Original issue reported on code.google.com by magn...@gmail.com on 30 Nov 2014 at 3:03

GoogleCodeExporter commented 9 years ago
Would something like this work for your situation (using a 
map-of-pointers-to-struct for Item in your config struct)?

[item "foo"]
active=true
sleep=12

[item "bar"]
active=false
sleep=49

Having multiple entities with the same (sub)section header is not currently 
supported, and I tend to think that it would add more confusion/complexity than 
value. With named subsections, as in the above example, it is obvious just by 
reading the section headers that the values under each header belong to 
different entities, making it easier to read (more explicit / less ambiguous) 
both for users and programs.

Original comment by speter....@gmail.com on 30 Nov 2014 at 3:14

GoogleCodeExporter commented 9 years ago
switching to that idea gives me the issue of then its saying

panic: map field for section must have string keys and  pointer-to-struct 
values: section "items"

which i assume means it wants map[string] and I want map[int] as id rather not 
have to convert a int to a string all the time

Original comment by magn...@gmail.com on 1 Dec 2014 at 10:51

GoogleCodeExporter commented 9 years ago
Currently only the string type is supported for subsection names (map keys). 
Conversion to int could be added if it was a common requirement, but it seems 
rather niche [1]. If you want to use integers as map keys, I'd suggest for now 
to copy the data from map[string]*item to a new map[int]*item in your program 
right after reading the configuration file; it should only add a few lines. (It 
is easier and more robust to convert the map once after parsing the file, 
rather than converting the key from int to string at each lookup.) If the same 
requirement comes up in several projects, we can revisit adding this conversion 
operation to gcfg.

In case you are using ints to specify the order of the items, you may also want 
to consider specifying the order using item names in a separate multi-value 
variable instead [2]. This also has the advantage that there is no need for 
renumbering when inserting/deleting items.

Either way, if you could provide more specific information about what kind of 
data your configuration contains, as well as any special requirements / 
constraints (e.g. need to maintain order for some configuration elements), it 
could make it easier to work out a solution. Also note that while gcfg aims to 
make handling of simple configuration data easy, it doesn't intend to cover 
every possible use case. If there are unusual constraints, it may be the case 
that a more versatile format (e.g. json/yaml) is more suited for your 
application. But I think that in many cases data can be organized into a 
suitable form.

[1] For instance, git is quite a complex tool with many configuration options 
(see http://git-scm.com/docs/git-config ), yet it manages without using ints in 
configuration keys. (The gcfg configuration syntax is based on that for git 
config.) Other formats that aim for simple configuration (such as Python's 
configparser or Java properties files) also don't have such a feature and yet 
seem to suffice for a large number of projects. Part of the reason why many 
projects are not using ints in configuration keys may be that integer 
representation can be ambiguous, e.g. "00", "0", and "-0" can all represent the 
same integer, making the use of int values as keys more error-prone than 
strings.

[2] For example:

    [items]
    item=foo
    item=bar

    [item "foo"]
    active=true
    sleep=12

    [item "bar"]
    active=false
    sleep=49

Original comment by speter....@gmail.com on 2 Dec 2014 at 2:15

GoogleCodeExporter commented 9 years ago
my layout is that i have physical hardware that programming wise is accessed 
via index 0-7
so each of those indexes needs its own configure line and subset of options on 
how to treat it

for now ill just add the code to change the string map to something more useful
since i have to double check i have no nil's hiding anyways

Original comment by magn...@gmail.com on 2 Dec 2014 at 6:28

GoogleCodeExporter commented 9 years ago
I see, it makes much more sense now, and it does seem like a somewhat unique 
constraint. So what you need is not really a slice (arbitrary number of sets of 
values) but rather an array (fixed number of sets of values). Although you 
should be able to get it to work with maps the way we've discussed so far, this 
enables some alternative approaches.

Subsections are primarily intended for cases where the user can arbitrarily 
add/remove sets of data, which is more flexibility than you need in this 
situation. It is this flexibility that requires dealing with nil pointers 
(missing data) and excess data (what if user specifies [item "9"]?).

If there is only one section for which you need 8 sets of values, I'd probably 
do something like this:

type Item struct {
    Name    string
    Enabled bool
    Sleep   int // or time.Duration
}

var cfg struct {
    // [item-0] etc
    Item_0, Item_1, Item_2, Item_3, Item_4, Item_5, Item_6, Item_7 Item
    // ... other sections
}

var items = [8]*Item{&cfg.Item_0, &cfg.Item_1, &cfg.Item_2, &cfg.Item_3,
    &cfg.Item_4, &cfg.Item_5, &cfg.Item_6, &cfg.Item_7}

This way you can just refer to the data as items[index] and not worry about nil 
pointers or the user specifying items with unexpected indexes.

In case there is a large amount of data (several sections) to be specified for 
each of 0-7, another alternative would be to use separate files for each index. 
(This has the additional advantage that you can easily use diff tools to 
compare the settings among indexes 0-7.)

Again, if this was a common requirement, I'd be willing to add support for 
mapping such sections to an array, but any of the discussed approaches should 
work with minimal additional caller-side code, and it's the first time I've 
seen such requirement, so I'd rather wait to see if it is needed by other 
projects as well.

Original comment by speter....@gmail.com on 3 Dec 2014 at 1:38

GoogleCodeExporter commented 9 years ago
Marking it WontFix for now, will reconsider in case such requirement comes up 
from multiple places.

Original comment by speter....@gmail.com on 14 Dec 2014 at 12:53

GoogleCodeExporter commented 9 years ago
forgot to comment on what I ended up doing
i did use a string map with numbers in the config file
which allows for gaps in the config
then i created the struct i wanted to use in the app and setup a function 
to transfer info and check defaults or out of range stuff to the struct in use 
in the app
this allows me to get the info i want and still use integers directly in my 
code base

Original comment by magn...@gmail.com on 14 Dec 2014 at 5:38