Skip to content

Commit f04607a

Browse files
authored
Merge pull request #1361 from urfave/dearchap-remove_reflect
Remove reflect calls for doc generation (#1259)
2 parents 372ee0a + 9fd3cc9 commit f04607a

18 files changed

Lines changed: 418 additions & 49 deletions

flag.go

Lines changed: 19 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,12 @@ type DocGenerationFlag interface {
117117
// GetValue returns the flags value as string representation and an empty
118118
// string if the flag takes no value at all.
119119
GetValue() string
120+
121+
// GetDefaultText returns the default text for this flag
122+
GetDefaultText() string
123+
124+
// GetEnvVars returns the env vars for this flag
125+
GetEnvVars() []string
120126
}
121127

122128
// VisibleFlag is an interface that allows to check if a flag is visible
@@ -299,55 +305,29 @@ func formatDefault(format string) string {
299305
}
300306

301307
func stringifyFlag(f Flag) string {
302-
fv := flagValue(f)
303-
304-
switch f := f.(type) {
305-
case *IntSliceFlag:
306-
return withEnvHint(flagStringSliceField(f, "EnvVars"),
307-
stringifyIntSliceFlag(f))
308-
case *Int64SliceFlag:
309-
return withEnvHint(flagStringSliceField(f, "EnvVars"),
310-
stringifyInt64SliceFlag(f))
311-
case *Float64SliceFlag:
312-
return withEnvHint(flagStringSliceField(f, "EnvVars"),
313-
stringifyFloat64SliceFlag(f))
314-
case *StringSliceFlag:
315-
return withEnvHint(flagStringSliceField(f, "EnvVars"),
316-
stringifyStringSliceFlag(f))
308+
// enforce DocGeneration interface on flags to avoid reflection
309+
df, ok := f.(DocGenerationFlag)
310+
if !ok {
311+
return ""
317312
}
318313

319-
placeholder, usage := unquoteUsage(fv.FieldByName("Usage").String())
314+
placeholder, usage := unquoteUsage(df.GetUsage())
315+
needsPlaceholder := df.TakesValue()
320316

321-
needsPlaceholder := false
322-
defaultValueString := ""
323-
val := fv.FieldByName("Value")
324-
if val.IsValid() {
325-
needsPlaceholder = val.Kind() != reflect.Bool
326-
defaultValueString = fmt.Sprintf(formatDefault("%v"), val.Interface())
327-
328-
if val.Kind() == reflect.String && val.String() != "" {
329-
defaultValueString = fmt.Sprintf(formatDefault("%q"), val.String())
330-
}
331-
}
332-
333-
helpText := fv.FieldByName("DefaultText")
334-
if helpText.IsValid() && helpText.String() != "" {
335-
needsPlaceholder = val.Kind() != reflect.Bool
336-
defaultValueString = fmt.Sprintf(formatDefault("%s"), helpText.String())
317+
if needsPlaceholder && placeholder == "" {
318+
placeholder = defaultPlaceholder
337319
}
338320

339-
if defaultValueString == formatDefault("") {
340-
defaultValueString = ""
341-
}
321+
defaultValueString := ""
342322

343-
if needsPlaceholder && placeholder == "" {
344-
placeholder = defaultPlaceholder
323+
if s := df.GetDefaultText(); s != "" {
324+
defaultValueString = fmt.Sprintf(formatDefault("%s"), s)
345325
}
346326

347327
usageWithDefault := strings.TrimSpace(usage + defaultValueString)
348328

349-
return withEnvHint(flagStringSliceField(f, "EnvVars"),
350-
fmt.Sprintf("%s\t%s", prefixedNames(f.Names(), placeholder), usageWithDefault))
329+
return withEnvHint(df.GetEnvVars(),
330+
fmt.Sprintf("%s\t%s", prefixedNames(df.Names(), placeholder), usageWithDefault))
351331
}
352332

353333
func stringifyIntSliceFlag(f *IntSliceFlag) string {

flag_bool.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,19 @@ func (f *BoolFlag) IsVisible() bool {
6363
return !f.Hidden
6464
}
6565

66+
// GetDefaultText returns the default text for this flag
67+
func (f *BoolFlag) GetDefaultText() string {
68+
if f.DefaultText != "" {
69+
return f.DefaultText
70+
}
71+
return fmt.Sprintf("%v", f.Value)
72+
}
73+
74+
// GetEnvVars returns the env vars for this flag
75+
func (f *BoolFlag) GetEnvVars() []string {
76+
return f.EnvVars
77+
}
78+
6679
// Apply populates the flag given the flag set and environment
6780
func (f *BoolFlag) Apply(set *flag.FlagSet) error {
6881
if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {

flag_duration.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,19 @@ func (f *DurationFlag) IsVisible() bool {
6363
return !f.Hidden
6464
}
6565

66+
// GetDefaultText returns the default text for this flag
67+
func (f *DurationFlag) GetDefaultText() string {
68+
if f.DefaultText != "" {
69+
return f.DefaultText
70+
}
71+
return f.GetValue()
72+
}
73+
74+
// GetEnvVars returns the env vars for this flag
75+
func (f *DurationFlag) GetEnvVars() []string {
76+
return f.EnvVars
77+
}
78+
6679
// Apply populates the flag given the flag set and environment
6780
func (f *DurationFlag) Apply(set *flag.FlagSet) error {
6881
if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {

flag_float64.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,20 @@ func (f *Float64Flag) GetUsage() string {
5555
// GetValue returns the flags value as string representation and an empty
5656
// string if the flag takes no value at all.
5757
func (f *Float64Flag) GetValue() string {
58-
return fmt.Sprintf("%f", f.Value)
58+
return fmt.Sprintf("%v", f.Value)
59+
}
60+
61+
// GetDefaultText returns the default text for this flag
62+
func (f *Float64Flag) GetDefaultText() string {
63+
if f.DefaultText != "" {
64+
return f.DefaultText
65+
}
66+
return f.GetValue()
67+
}
68+
69+
// GetEnvVars returns the env vars for this flag
70+
func (f *Float64Flag) GetEnvVars() []string {
71+
return f.EnvVars
5972
}
6073

6174
// IsVisible returns true if the flag is not hidden, otherwise false

flag_float64_slice.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ func (f *Float64SliceFlag) IsSet() bool {
9595
// String returns a readable representation of this value
9696
// (for usage defaults)
9797
func (f *Float64SliceFlag) String() string {
98-
return FlagStringer(f)
98+
return withEnvHint(f.GetEnvVars(), stringifyFloat64SliceFlag(f))
9999
}
100100

101101
// Names returns the names of the flag
@@ -132,6 +132,19 @@ func (f *Float64SliceFlag) IsVisible() bool {
132132
return !f.Hidden
133133
}
134134

135+
// GetDefaultText returns the default text for this flag
136+
func (f *Float64SliceFlag) GetDefaultText() string {
137+
if f.DefaultText != "" {
138+
return f.DefaultText
139+
}
140+
return f.GetValue()
141+
}
142+
143+
// GetEnvVars returns the env vars for this flag
144+
func (f *Float64SliceFlag) GetEnvVars() []string {
145+
return f.EnvVars
146+
}
147+
135148
// Apply populates the flag given the flag set and environment
136149
func (f *Float64SliceFlag) Apply(set *flag.FlagSet) error {
137150
if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {

flag_generic.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,19 @@ func (f *GenericFlag) IsVisible() bool {
7171
return !f.Hidden
7272
}
7373

74+
// GetDefaultText returns the default text for this flag
75+
func (f *GenericFlag) GetDefaultText() string {
76+
if f.DefaultText != "" {
77+
return f.DefaultText
78+
}
79+
return f.GetValue()
80+
}
81+
82+
// GetEnvVars returns the env vars for this flag
83+
func (f *GenericFlag) GetEnvVars() []string {
84+
return f.EnvVars
85+
}
86+
7487
// Apply takes the flagset and calls Set on the generic flag with the value
7588
// provided by the user for parsing by the flag
7689
func (f GenericFlag) Apply(set *flag.FlagSet) error {

flag_int.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,19 @@ func (f *IntFlag) IsVisible() bool {
6363
return !f.Hidden
6464
}
6565

66+
// GetDefaultText returns the default text for this flag
67+
func (f *IntFlag) GetDefaultText() string {
68+
if f.DefaultText != "" {
69+
return f.DefaultText
70+
}
71+
return f.GetValue()
72+
}
73+
74+
// GetEnvVars returns the env vars for this flag
75+
func (f *IntFlag) GetEnvVars() []string {
76+
return f.EnvVars
77+
}
78+
6679
// Apply populates the flag given the flag set and environment
6780
func (f *IntFlag) Apply(set *flag.FlagSet) error {
6881
if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {

flag_int64.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,19 @@ func (f *Int64Flag) IsVisible() bool {
6363
return !f.Hidden
6464
}
6565

66+
// GetDefaultText returns the default text for this flag
67+
func (f *Int64Flag) GetDefaultText() string {
68+
if f.DefaultText != "" {
69+
return f.DefaultText
70+
}
71+
return f.GetValue()
72+
}
73+
74+
// GetEnvVars returns the env vars for this flag
75+
func (f *Int64Flag) GetEnvVars() []string {
76+
return f.EnvVars
77+
}
78+
6679
// Apply populates the flag given the flag set and environment
6780
func (f *Int64Flag) Apply(set *flag.FlagSet) error {
6881
if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {

flag_int64_slice.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ func (f *Int64SliceFlag) IsSet() bool {
9696
// String returns a readable representation of this value
9797
// (for usage defaults)
9898
func (f *Int64SliceFlag) String() string {
99-
return FlagStringer(f)
99+
return withEnvHint(f.GetEnvVars(), stringifyInt64SliceFlag(f))
100100
}
101101

102102
// Names returns the names of the flag
@@ -133,6 +133,19 @@ func (f *Int64SliceFlag) IsVisible() bool {
133133
return !f.Hidden
134134
}
135135

136+
// GetDefaultText returns the default text for this flag
137+
func (f *Int64SliceFlag) GetDefaultText() string {
138+
if f.DefaultText != "" {
139+
return f.DefaultText
140+
}
141+
return f.GetValue()
142+
}
143+
144+
// GetEnvVars returns the env vars for this flag
145+
func (f *Int64SliceFlag) GetEnvVars() []string {
146+
return f.EnvVars
147+
}
148+
136149
// Apply populates the flag given the flag set and environment
137150
func (f *Int64SliceFlag) Apply(set *flag.FlagSet) error {
138151
if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {

flag_int_slice.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ func (f *IntSliceFlag) IsSet() bool {
107107
// String returns a readable representation of this value
108108
// (for usage defaults)
109109
func (f *IntSliceFlag) String() string {
110-
return FlagStringer(f)
110+
return withEnvHint(f.GetEnvVars(), stringifyIntSliceFlag(f))
111111
}
112112

113113
// Names returns the names of the flag
@@ -144,6 +144,19 @@ func (f *IntSliceFlag) IsVisible() bool {
144144
return !f.Hidden
145145
}
146146

147+
// GetDefaultText returns the default text for this flag
148+
func (f *IntSliceFlag) GetDefaultText() string {
149+
if f.DefaultText != "" {
150+
return f.DefaultText
151+
}
152+
return f.GetValue()
153+
}
154+
155+
// GetEnvVars returns the env vars for this flag
156+
func (f *IntSliceFlag) GetEnvVars() []string {
157+
return f.EnvVars
158+
}
159+
147160
// Apply populates the flag given the flag set and environment
148161
func (f *IntSliceFlag) Apply(set *flag.FlagSet) error {
149162
if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {

0 commit comments

Comments
 (0)