Skip to content

Commit

Permalink
chore: refactor file expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
omissis committed Aug 10, 2022
1 parent c3e0c1d commit f4f563c
Show file tree
Hide file tree
Showing 10 changed files with 409 additions and 272 deletions.
20 changes: 7 additions & 13 deletions internal/arch/file/except/except.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,20 @@ import (
"goarkitect/internal/arch/rule"
)

type evaluateFunc func(filePath string) bool

func NewExpression(
evaluate evaluateFunc,
) *Expression {
return &Expression{
evaluate: evaluate,
}
type Expression interface {
Evaluate(rb rule.Builder)
}

type Expression struct {
evaluate func(filePath string) bool
}
type evaluateFunc func(filePath string) bool

type baseExpression struct{}

func (e Expression) Evaluate(rb rule.Builder) {
func (e baseExpression) evaluate(rb rule.Builder, eval evaluateFunc) {
frb := rb.(*file.RuleBuilder)

nf := make([]string, 0)
for _, filePath := range frb.GetFiles() {
if e.evaluate(filePath) {
if eval(filePath) {
nf = append(nf, filePath)
}
}
Expand Down
29 changes: 21 additions & 8 deletions internal/arch/file/except/this.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
package except

import "path/filepath"

func This(value string) *Expression {
return NewExpression(
func(filePath string) bool {
return filepath.Base(filePath) != value
},
)
import (
"goarkitect/internal/arch/rule"
"path/filepath"
)

func This(value string) *ThisExpression {
return &ThisExpression{
value: value,
}
}

type ThisExpression struct {
baseExpression

value string
}

func (e ThisExpression) Evaluate(rb rule.Builder) {
e.evaluate(rb, func(filePath string) bool {
return filepath.Base(filePath) != e.value
})
}
61 changes: 39 additions & 22 deletions internal/arch/file/should/end_with.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,44 @@ import (
"path/filepath"
)

func EndWith(suffix string, opts ...Option) *Expression {
ls := len(suffix)

return NewExpression(
func(_ rule.Builder, filePath string) bool {
fileName := filepath.Base(filePath)

lf := len(fileName)

return ls <= lf && fileName[lf-ls:] != suffix
},
func(filePath string, options options) rule.Violation {
format := "file's name '%s' does not end with '%s'"
if options.negated {
format = "file's name '%s' does end with '%s'"
}

return rule.NewViolation(
fmt.Sprintf(format, filepath.Base(filePath), suffix),
)
},
opts...,
func EndWith(suffix string, opts ...Option) *endWithExpression {
expr := &endWithExpression{
suffix: suffix,
}

for _, opt := range opts {
opt.apply(&expr.options)
}

return expr
}

type endWithExpression struct {
baseExpression

suffix string
}

func (e endWithExpression) Evaluate(rb rule.Builder) []rule.Violation {
return e.evaluate(rb, e.doEvaluate, e.getViolation)
}

func (e endWithExpression) doEvaluate(rb rule.Builder, filePath string) bool {
fileName := filepath.Base(filePath)

ls := len(e.suffix)
lf := len(fileName)

return ls <= lf && fileName[lf-ls:] != e.suffix
}

func (e endWithExpression) getViolation(filePath string) rule.Violation {
format := "file's name '%s' does not end with '%s'"
if e.options.negated {
format = "file's name '%s' does end with '%s'"
}

return rule.NewViolation(
fmt.Sprintf(format, filepath.Base(filePath), e.suffix),
)
}
62 changes: 38 additions & 24 deletions internal/arch/file/should/exist.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,43 @@ import (
"path/filepath"
)

func Exist(opts ...Option) *Expression {
return NewExpression(
func(rb rule.Builder, filePath string) bool {
if _, err := os.Stat(filePath); err != nil {
if !os.IsNotExist(err) {
rb.AddError(err)
}

return true
}

return false
},
func(filePath string, options options) rule.Violation {
format := "file '%s' does not exist"
if options.negated {
format = "file '%s' does exist"
}

return rule.NewViolation(
fmt.Sprintf(format, filepath.Base(filePath)),
)
},
opts...,
func Exist(opts ...Option) *existExpression {
expr := &existExpression{}

for _, opt := range opts {
opt.apply(&expr.options)
}

return expr
}

type existExpression struct {
baseExpression
}

func (e existExpression) Evaluate(rb rule.Builder) []rule.Violation {
return e.evaluate(rb, e.doEvaluate, e.getViolation)
}

func (e existExpression) doEvaluate(rb rule.Builder, filePath string) bool {
if _, err := os.Stat(filePath); err != nil {
if !os.IsNotExist(err) {
rb.AddError(err)
}

return true
}

return false
}

func (e existExpression) getViolation(filePath string) rule.Violation {
format := "file '%s' does not exist"
if e.options.negated {
format = "file '%s' does exist"
}

return rule.NewViolation(
fmt.Sprintf(format, filepath.Base(filePath)),
)
}
113 changes: 62 additions & 51 deletions internal/arch/file/should/have_content_matching.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,65 +10,76 @@ import (
"golang.org/x/exp/slices"
)

func HaveContentMatching(want []byte, opts ...Option) *Expression {
return NewExpression(
func(rb rule.Builder, filePath string) bool {
data, err := os.ReadFile(filePath)
if err != nil {
rb.AddError(err)
return true
}
func HaveContentMatching(want []byte, opts ...Option) *haveContentMatchingExpression {
expr := &haveContentMatchingExpression{
want: want,
}

match := "SINGLE"
separator := []byte("\n")
for _, opt := range opts {
switch opt.(type) {
case IgnoreNewLinesAtTheEndOfFile:
data = bytes.TrimRight(data, "\n")
want = bytes.TrimRight(want, "\n")
case IgnoreCase:
data = bytes.ToLower(data)
want = bytes.ToLower(want)
case MatchSingleLines:
match = "MULTIPLE"
if sep := opt.(MatchSingleLines).Separator; sep != "" {
separator = []byte(sep)
}
}
}
for _, opt := range opts {
opt.apply(&expr.options)
}

if match == "SINGLE" {
return slices.Compare(data, want) != 0
}
return expr
}

linesData := bytes.Split(data, separator)
for _, ld := range linesData {
if slices.Compare(ld, want) != 0 {
return true
}
}
type haveContentMatchingExpression struct {
baseExpression

return false
},
func(filePath string, options options) rule.Violation {
format := "file '%s' does not have content matching '%s'"
want []byte
}

if options.matchSingleLines {
format = "file '%s' does not have all lines matching '%s'"
}
func (e haveContentMatchingExpression) Evaluate(rb rule.Builder) []rule.Violation {
return e.evaluate(rb, e.doEvaluate, e.getViolation)
}

if options.negated {
format = "file '%s' does have content matching '%s'"
}
func (e haveContentMatchingExpression) doEvaluate(rb rule.Builder, filePath string) bool {
data, err := os.ReadFile(filePath)
if err != nil {
rb.AddError(err)

return true
}

if options.negated && options.matchSingleLines {
format = "file '%s' does have all lines matching '%s'"
if e.options.ignoreNewLinesAtTheEndOfFile {
data = bytes.TrimRight(data, "\n")
e.want = bytes.TrimRight(e.want, "\n")
}

if e.options.ignoreCase {
data = bytes.ToLower(data)
e.want = bytes.ToLower(e.want)
}

if e.options.matchSingleLines {
linesData := bytes.Split(data, []byte(e.options.matchSingleLinesSeparator))
for _, ld := range linesData {
if slices.Compare(ld, e.want) != 0 {
return true
}
}

return false
}

return slices.Compare(data, e.want) != 0
}

func (e haveContentMatchingExpression) getViolation(filePath string) rule.Violation {
format := "file '%s' does not have content matching '%s'"

if e.options.matchSingleLines {
format = "file '%s' does not have all lines matching '%s'"
}

if e.options.negated {
format = "file '%s' does have content matching '%s'"
}

if e.options.negated && e.options.matchSingleLines {
format = "file '%s' does have all lines matching '%s'"
}

return rule.NewViolation(
fmt.Sprintf(format, filepath.Base(filePath), want),
)
},
opts...,
return rule.NewViolation(
fmt.Sprintf(format, filepath.Base(filePath), e.want),
)
}
Loading

0 comments on commit f4f563c

Please sign in to comment.