Why the ruby syntax?
voronoipotato opened this issue · 41 comments
I know this is a design decision, but I feel that it should be more like go. It seems less intuitive to have something written in go, for go, that looks like ruby simply because it was inspired by a ruby tool.
Could use YAML ?
YAML might work actually. I'm not seeing any standard YAML go library but we could use libYAML.
I think, yaml is good but yaml isn't DSL which people can judge the conditions as human readable.
We could literally just write it like go code. The problem with writing it like ruby is it makes an assumption that you know and are familiar with ruby code.
You might be right, but lets see what we can do with the README example.
gom 'github.com/mattn/go-runewidth', :tag => 'go1'
gom 'github.com/mattn/go-scan', :commit => 'ecb144fb1f2848a24ebfdadf8e64380406d87206'
gom 'github.com/daviddengcn/go-colortext'
gom 'github.com/mattn/go-ole', :goos => 'windows'
Could be written:
- gom: github.com/mattn/go-runewidth
tag: go1
- gom: github.com/mattn/go-scan
commit: ecb144fb1f2848a24ebfdadf8e64380406d87206
- gom: github.com/daviddengcn/go-colortext
- gom: github.com/mattn/go-ole
goos: windows
Personally I'd probably use more natural terms, like uri
or dep
instead of gom
, and so forth, but that's a minor point.
If there is some concern that additional top-level info will be required one day, then adding a top-level mapping would do the trick. e.g.
dependencies:
- gom: ...
Of course, thinking about it a bit more, you are using your own parser currently, so you could do it any way you wanted, which really does make the use of ruby symbols (e.g. :tag
) seem a bit odd.
What would the go code version look like?
How about this in yaml?
group :production, :development do
gom 'github.com/mattn/go-ole', :goos => 'windows'
end
There's also the encoding/json built in, which would definitely eliminate potential errors. However some readability would be lost. Then there's this https://github.com/emilsjolander/goson
I don't think ruby's syntax is best for gom. but I think yaml is not better than ruby's syntax.
I agree. If you need that level of expressiveness then it's either verbose XML or a DSL. If you want to do it in the most Go-ish way possible I suspect it would have to be by approximating functions and function chaining.
Gom("github.com/mattn/go-runewidth").Tag("go1")
Gom("github.com/mattn/go-scan").Commit("ecb144fb1f2848a24ebfdadf8e64380406d87206")
Gom("github.com/daviddengcn/go-colortext")
Gom("github.com/mattn/go-ole").Os("windows")
Group("production", "development") {
Gom("github.com/mattn/go-ole").Os("windows")
}
What about a JSON file like Bower uses it?
Everybody knows JSON, it's easily extendable and go hast built-in support for it.
A definition file could look like this:
{
dependencies: [
{
gom: "github.com/mattn/go-runewidth",
tag: "go1"
},
{
gom: "github.com/mattn/go-scan",
commit: "ecb144fb1f2848a24ebfdadf8e64380406d87206"
},
{
gom: "github.com/daviddengcn/go-colortext"
},
{
gom: "github.com/mattn/go-ole",
goos: "windows"
},
]
}
I don't see any advantage to using JSON over YAML.
I cam across QML for Go today. After looking at the QML, it reminded me of this issue b/c the QML looks a bit like Go (sort of like a GO and CSS hybrid). Given that, Gom could do something like:
Gom {
uri: github.com/mattn/go-runewidth
tag: go1
}
Gom {
uri: github.com/mattn/go-scan
commit: ecb144fb1f2848a24ebfdadf8e64380406d87206
}
Gom { uri: github.com/daviddengcn/go-colortext }
Gom {
uri: github.com/mattn/go-ole
os: windows
}
Group production, development {
Gom {
uri: github.com/mattn/go-ole
os: windows
}
}
It looks more verbose, but entries could be condensed, e.g.
Gom { uri: github.com/mattn/go-ole os: windows }
as long as there are no spaces involved, in which case quotes would be necessary anyway I think. Either that or ;
could used to separate entries on the same line.
I think this is better then the Ruby syntax in that it has a fairly Go look and feel.
@mattn BTW, per your question about expressing the following in YAML.
group :production, :development do
gom 'github.com/mattn/go-ole', :goos => 'windows'
end
I don't think there is really a particularly better way then just adding groups to each entry, e.g.
- gom: github.com/mattn/go-ole
group: production, development
os: windows
Redundant but simple.
QML is too fat for gom.
BTW, per your question about expressing the following in YAML.
How do you write below in YAML? two section?
group :production, :development do
gom 'github.com/daviddengcn/go-colortext-for-windows', :goos => [:windows]
gom 'github.com/daviddengcn/go-colortext-for-linux', :goos => [:linux]
end
@mattn Oh no, I wasn't suggesting you actually use QML! That was just my inspiration for the notation. I meant that the current parser could be modified to parse a syntax that was similar to QML's. Actually, it is very similar to CSS too, if that helps give a different perspective on it.
As for the YAML, you would do it like so:
- gom: github.com/daviddengcn/go-colortext-for-windows
goos: [windows]
group: [production, development]
- gom: github.com/daviddengcn/go-colortext-for-linux
goos: [linux]
group: [production, development]
Why goos
and not just os
, btw?
also I think dep instead of gom might be more descriptive.
+1 for JSON, since it's the only notation language supported natively by Go
Go's JSON doesn't allow to write comment. It's too strictly.
@mattn what about if we using newer Ruby hash syntax:
gom 'github.com/mattn/go-scan', commit: 'ecb144fb1f2848a24ebfdadf8e64380406d87206'
Optionally, we can also drop "gom" keyword, so it will be:
github.com/mattn/go-scan, commit: 'ecb144fb1f2848a24ebfdadf8e64380406d87206'
And there is no symbol for the group:
group "production", "development" {
github.com/mattn/go-scan, commit: 'ecb144fb1f2848a24ebfdadf8e64380406d87206'
{
or
group "production", "development":
github.com/mattn/go-scan, commit: 'ecb144fb1f2848a24ebfdadf8e64380406d87206'
We can also define group as part of the line:
github.com/mattn/go-scan, commit: 'ecb144fb1f2848a24ebfdadf8e64380406d87206', group: "production, development"
What do you think?
The problem with using ruby syntax is there's no reason why any Go developer would be familiar with it. You lose all advantages of a DSL when you go outside the domain. We could also use lisp, or perl, or even haskell but those aren't going to be helpful but to a small subset of developers.
Surprised that no one gave a feedback on @trans Go-ish proposal on #5 (comment)
I'd change the Group
curly braces by parentheses though, so it could be feasible to implement and idiomatic, too:
Gom("github.com/mattn/go-runewidth").Tag("go1")
Gom("github.com/mattn/go-scan").Commit("ecb144fb1f2848a24ebfdadf8e64380406d87206")
Gom("github.com/daviddengcn/go-colortext")
Gom("github.com/mattn/go-ole").Os("windows")
Group("production", "development") (
Gom("github.com/mattn/go-ole").Os("windows")
)
In other hand, I know you guys probably see rubygems and bundle as the way to follow, but I don't really like having so similar specs and naming to Ruby. Thus, I'd just call .gom
to the current Gomfile
: cleaner, not intrusive and not intented to be a copy of anything.
EDIT
Another approach, totally OOP-ish:
Gom("github.com/mattn/go-runewidth").Tag("go1")
Gom("github.com/mattn/go-scan").Commit("ecb144fb1f2848a24ebfdadf8e64380406d87206")
Gom("github.com/daviddengcn/go-colortext")
Gom("github.com/mattn/go-ole").Os("windows")
Group("production", "development").Gom("github.com/mattn/go-ole").Os("windows")
+1 for yaml
I like the go function chaining style
Just occurred to me that method chaining across newlines should be possible. So it could be written:
Gom("github.com/mattn/go-runewidth").
Tag("go1")
Gom("github.com/mattn/go-scan").
Commit("ecb144fb1f2848a24ebfdadf8e64380406d87206")
Gom("github.com/daviddengcn/go-colortext")
Gom("github.com/mattn/go-ole").
Os("windows")
Group("production", "development").
Gom("github.com/mattn/go-ole").
Os("windows")
I wrote example to use go syntax, hmm go is awsome but seems not useful to define DSL. .
should be located at end of line. And compiler doesn't allow to locate .
at leading of the line. gofmt
breaks nesting for third line.
package main
import (
"fmt"
)
var goms []*TGom
type TGroup struct {
envs []string
}
type TGom struct {
name string
commit string
envs []string
os []string
}
func Group(envs ...string) *TGroup {
return &TGroup{envs}
}
func (group *TGroup) Gom(name string) *TGom {
gom := &TGom{name, "", group.envs, []string{}}
goms = append(goms, gom)
return gom
}
func Gom(name string) *TGom {
gom := &TGom{name, "", []string{}, []string{}}
goms = append(goms, gom)
return gom
}
func (gom *TGom) Commit(commit string) *TGom {
gom.commit = commit
return gom
}
func (gom *TGom) OS(os ...string) *TGom {
gom.os = os
return gom
}
func main() {
Group("production", "development").
Gom("github.com/mattn/go-ole").
Commit("ecb144fb1f2848a24ebfdadf8e64380406d87206")
Gom("github.com/mattn/go-ole").
Commit("ecb144fb1f2848a24ebfdadf8e64380406d87206")
for _, gom := range goms {
fmt.Println(gom.name, gom.commit)
}
}
You might report the nesting issue as a bug in gofmt. Seems to me it should honor indentation.
No, it's not a problem just for go. It's a related issue of identation for Gomfile.
For example, below is a valid indentaion for go.
a := NewSomething().
a.SetAttr("foo", "bar").
SetAttr("bar", "baz").
SetAttr("baz", "foo").
But Gomfile have a mean for indentation that different from go.
It's valid but IMO if the design calls for such indention, e.g.
a := NewSomething().
a.SetAttr("foo", "bar").
SetAttr("bar", "baz").
SetAttr("baz", "foo")
Then gofmt needs to follow along and not make an assumption about what the significance of that indention is. In this particular case we know that SetAttr() is going to return a
so indenting like this doesn't really make sense, but there is no way for gofmt to know that. If could be the SetAttr returned a new object every time instead, then this indention would make perfect sense and gofmt should leave it be.
I like the gpm Godeps format.. https://github.com/pote/gpm
github.com/nu7hatch/gotrail v0.0.2
github.com/replicon/fast-archiver v1.02
launchpad.net/gocheck r2013.03.03 # Bazaar repositories are supported
code.google.com/p/go.example/hello/... ae081cd1d6cc # And so are Mercurial ones
@pkieltyka The format can't define extra package. For example, packages just for windows.
I see.. are people using a :platform directive to specify OS-specific libraries? I thought that would be handled by go's build tool via the standard // +build linux darwin etc
Currently, gom gen gomfile
doesn't handle that.
I've also noticed a lot of Go developers using the classic INI format.. it's pretty clean: https://github.com/Unknwon/goconfig
This is what https://github.com/gpmgo/gopm does and it's nice .. their example:
[deps]
github.com/pilu/fresh=
github.com/astaxie/beego=tag:v0.9.0
you could do something like
[deps:windows]
[deps -windows +linux]
or whatever you come up with ..
+1 for something in pure Go
Otherwise something in an standard format that can be written / read with external tooling e.g. JSON, JSON5, CSON, YAML
https://github.com/hashicorp/hcl might also be an acceptable solution?
Awkward discussion. Even if one doesn't know ruby it's still pretty simple to grasp the current syntax. I don't think the proposed syntax changes have much value other than "it should not remind me of ruby".
On the other hand machine readable would be nice - that's a fair point.
It's unfortunate that JSON doesn't allow for comments - but I would still vote for it.
Please no YAML.
I don't see the value from the syntax change unless we could make it more readable, and don't like the idea to introduce another package to parse the configuration which could be done with only few lines of code.
I agree with @jinzhu, changing the Gomfile syntax produces more works with no remarkable value at this time.