Skip to content

Commit

Permalink
Support inline struct type
Browse files Browse the repository at this point in the history
  • Loading branch information
kujtimiihoxha committed Apr 27, 2020
1 parent 3db11eb commit 715ed78
Show file tree
Hide file tree
Showing 2 changed files with 207 additions and 1 deletion.
56 changes: 55 additions & 1 deletion code.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ type TypeOptions func(t *Type)
// FunctionType is used in Type to specify a method type (e.x func(sting) int).
type FunctionType Function

// StructType is used in Type to specify a struct type (e.x struct{}).
type StructType Struct

// Type represents a type e.x `string`, `context.Context`...
// the type is represented by 2 main parameters.
//
Expand Down Expand Up @@ -84,6 +87,11 @@ type Type struct {
Value Type
}

// Struct is used for inline struct types
// e.x
// var a struct{}
Struct *StructType

// RawType is used to specify complex types (e.x map[string]*test.SomeStruct)
// if the raw type is not nil all the other parameters will be ignored.
RawType *jen.Statement
Expand Down Expand Up @@ -275,6 +283,12 @@ func MapTypeOption(key Type, value Type) TypeOptions {
}
}
}
// StructTypeOption sets the map type.
func StructTypeOption(st StructType) TypeOptions {
return func(t *Type) {
t.Struct = &st
}
}

// NewType creates the type with the qualifier and options given.
//
Expand Down Expand Up @@ -371,6 +385,12 @@ func NewStruct(name string, docs ...Comment) *Struct {
docs: docs,
}
}
// NewStructType creates a new struct type with the given fields
func NewStructType(fields ...StructField) *StructType {
return &StructType{
Fields: fields,
}
}

// NewStructWithFields creates a new structure with the given name and fields,
// there is also an optional list of documentation comments that you can add to the variable
Expand Down Expand Up @@ -520,6 +540,10 @@ func (t Type) Code() *jen.Statement {
code.Add(t.Function.Code())
return code
}
if t.Struct != nil {
code.Add(t.Struct.Code())
return code
}
if t.Import != nil {
if t.Import.Alias != "" {
code.Id(t.Import.Alias).Dot(t.Qualifier)
Expand Down Expand Up @@ -552,11 +576,12 @@ func (t Type) String() string {
}
return s
}
if t.ArrayType != nil || t.Variadic || t.MapType != nil {
if t.ArrayType != nil || t.Variadic || t.MapType != nil || t.Struct != nil {
code := jen.Func().Id("_").Params(t.Code()).Block()
s := code.GoString()
s = strings.TrimPrefix(s, "func _(")
s = strings.TrimSuffix(s, ") {}")
s = strings.TrimSuffix(s, ") {\n}")
return s
}
return codeString(t)
Expand Down Expand Up @@ -690,6 +715,35 @@ func (m *FunctionType) Docs() []Comment {
// We only implement this so we implement the Code interface.
func (m *FunctionType) AddDocs(_ ...Comment) {}

// Code returns the jen representation of the struct type.
func (s *StructType) Code() *jen.Statement {
code := &jen.Statement{}
return code.Struct(fieldList(s.Fields)...)
}

// String returns the go code string of the struct type.
// because the renderer does not render only struct types we create a dummy structure to add the struct type field to
// than we remove everything besides the struct type.
func (s *StructType) String() string {
//// Hack to get the reader to not panic in function types
code := jen.Func().Id("_").Params(s.Code()).Block()
str := code.GoString()
str = strings.TrimPrefix(str, "func _(")
str = strings.TrimSuffix(str, ") {}")
str = strings.TrimSuffix(str, ") {\n}")
//// -----
return str
}

// Docs does nothing for the struct type code.
func (s *StructType) Docs() []Comment {
return nil
}

// AddDocs does nothing for the struct type code.
// We only implement this so we implement the Code interface.
func (s *StructType) AddDocs(_ ...Comment) {}

// Code returns the jen representation of the function.
func (f *Function) Code() *jen.Statement {
code := &jen.Statement{}
Expand Down
152 changes: 152 additions & 0 deletions code_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1259,6 +1259,7 @@ func TestType_Code(t *testing.T) {
Method *FunctionType
Pointer bool
ArrayType *Type
StructType *StructType
MapType *struct {
Key Type
Value Type
Expand Down Expand Up @@ -1415,6 +1416,13 @@ func TestType_Code(t *testing.T) {
},
want: jen.Map(jen.Id("string")).Add(jen.Index().Add(jen.Map(jen.String()).Add(jen.Id("ast").Dot("File")))),
},
{
name: "Should return the correct jen representation of an struct type",
fields: fields{
StructType:NewStructType(),
},
want: jen.Add(jen.Struct()),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand All @@ -1426,6 +1434,7 @@ func TestType_Code(t *testing.T) {
Pointer: tt.fields.Pointer,
ArrayType: tt.fields.ArrayType,
MapType: tt.fields.MapType,
Struct: tt.fields.StructType,
Qualifier: tt.fields.Qualifier,
}
if got := tp.Code(); !reflect.DeepEqual(got, tt.want) {
Expand All @@ -1442,6 +1451,7 @@ func TestType_String(t *testing.T) {
Function *FunctionType
Pointer bool
ArrayType *Type
StructType *StructType
MapType *struct {
Key Type
Value Type
Expand Down Expand Up @@ -1627,6 +1637,20 @@ func TestType_String(t *testing.T) {
},
want: "map[string][]map[string]ast.File",
},
{
name: "Should return the correct string of an struct type",
fields: fields{
StructType:NewStructType(),
},
want: "struct{}",
},
{
name: "Should return the correct string of an struct type with fields",
fields: fields{
StructType:NewStructType(*NewStructField("A", NewType("string"))),
},
want: "struct {\n\tA string\n}",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand All @@ -1636,6 +1660,7 @@ func TestType_String(t *testing.T) {
Function: tt.fields.Function,
Pointer: tt.fields.Pointer,
ArrayType: tt.fields.ArrayType,
Struct: tt.fields.StructType,
MapType: tt.fields.MapType,
Variadic: tt.fields.Variadic,
Qualifier: tt.fields.Qualifier,
Expand Down Expand Up @@ -4145,3 +4170,130 @@ func TestRawCode_String(t *testing.T) {
})
}
}

func TestStructType_AddDocs(t *testing.T) {
type args struct {
in0 []Comment
}
tests := []struct {
name string
s StructType
args args
}{
{
name: "Should do nothing",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
})
}
}

func TestStructType_Code(t *testing.T) {
tests := []struct {
name string
s StructType
want *jen.Statement
}{
{
name: "Should return the correct jen representation of a struct type",
s: StructType{},
want: jen.Struct(),
},
{
name: "Should return the correct jen representation of a struct type with fields",
s: StructType{Fields: []StructField{*NewStructField("test", NewType("string"))},
},
want: jen.Struct(NewStructField("test", NewType("string")).Code()),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.s.Code(); !reflect.DeepEqual(got, tt.want) {
t.Errorf("Code() = %v, want %v", got, tt.want)
}
})
}
}

func TestStructType_Docs(t *testing.T) {
tests := []struct {
name string
s StructType
want []Comment
}{
{
name:"Should do nothing",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.s.Docs(); !reflect.DeepEqual(got, tt.want) {
t.Errorf("Docs() = %v, want %v", got, tt.want)
}
})
}
}

func TestStructType_String(t *testing.T) {
tests := []struct {
name string
s StructType
want string
}{
{
name: "Should return the correct jen representation of a struct type",
s: StructType{
},
want: "struct{}",
},
{
name: "Should return the correct jen representation of a struct type with fields",
s: StructType{
Fields: []StructField{*NewStructField("test", NewType("string"))},
},
want: "struct {\n\ttest string\n}",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.s.String(); got != tt.want {
t.Errorf("String() = %v, want %v", got, tt.want)
}
})
}
}

func TestStructTypeOption(t *testing.T) {
type args struct {
tp Type
s StructType
}
tests := []struct {
name string
args args
want Type
}{
{
name: "Should add the struct type to the type",
args: args{
tp: NewType(""),
s: *NewStructType(),
},
want: Type{
Qualifier: "",
Struct: NewStructType(),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := StructTypeOption(tt.args.s)
got(&tt.args.tp)
if !reflect.DeepEqual(tt.args.tp, tt.want) {
t.Errorf("Type = %v, want %v", tt.args.tp, tt.want)
}
})
}
}

0 comments on commit 715ed78

Please sign in to comment.