diff --git a/pkg/obioptions/version.go b/pkg/obioptions/version.go index c712563..11a9013 100644 --- a/pkg/obioptions/version.go +++ b/pkg/obioptions/version.go @@ -8,7 +8,7 @@ import ( // corresponds to the last commit, and not the one when the file will be // commited -var _Commit = "13ff892" +var _Commit = "e065e29" var _Version = "Release 4.4.0" // Version returns the version of the obitools package. diff --git a/pkg/obiseq/language.go b/pkg/obiseq/language.go index 40e1a75..26c7afc 100644 --- a/pkg/obiseq/language.go +++ b/pkg/obiseq/language.go @@ -1,6 +1,7 @@ package obiseq import ( + "errors" "fmt" "reflect" "regexp" @@ -145,14 +146,14 @@ var OBILang = gval.NewLanguage( ismap := obiutils.IsAMap(args[0]) return ismap, nil }), + gval.Function("isvector", func(args ...interface{}) (interface{}, error) { + isvector := obiutils.IsASlice(args[0]) + return isvector, nil + }), gval.Function("sprintf", func(args ...interface{}) (interface{}, error) { text := fmt.Sprintf(args[0].(string), args[1:]...) return text, nil }), - gval.Function("gsub", func(args ...interface{}) (interface{}, error) { - text := strings.ReplaceAll(args[0].(string), args[1].(string), args[2].(string)) - return text, nil - }), gval.Function("subspc", func(args ...interface{}) (interface{}, error) { text := strings.ReplaceAll(args[0].(string), " ", "_") return text, nil @@ -181,6 +182,14 @@ var OBILang = gval.NewLanguage( } return val, nil }), + gval.Function("string", func(args ...interface{}) (interface{}, error) { + val, err := obiutils.InterfaceToString(args[0]) + + if err != nil { + log.Fatalf("%v cannot be converted to a string value", args[0]) + } + return val, nil + }), gval.Function("ifelse", func(args ...interface{}) (interface{}, error) { if args[0].(bool) { return args[1], nil @@ -192,13 +201,52 @@ var OBILang = gval.NewLanguage( composition := (args[0].(*BioSequence)).Composition() return float64(composition['g']-composition['c']) / float64(composition['g']+composition['c']), nil }), + gval.Function("qualities", func(args ...interface{}) (interface{}, error) { + qualities := (args[0].(*BioSequence)).Qualities() + rep := make([]interface{}, len(qualities)) + for i, q := range qualities { + rep[i] = float64(q) + } + return rep, nil + }), + gval.Function("elementof", func(args ...interface{}) (interface{}, error) { + if obiutils.IsASlice(args[0]) { + pos, err := obiutils.InterfaceToInt(args[1]) + if err != nil { + return nil, err + } + if slice, ok := args[0].([]interface{}); ok { + return slice[pos], nil + } else { + return nil, errors.New("obi: first argument incorrect slice") + } + + } else if obiutils.IsAMap(args[0]) { + pos, err := obiutils.InterfaceToString(args[1]) + if err != nil { + return nil, err + } + if m, ok := args[0].(map[string]interface{}); ok { + return m[pos], nil + } else { + return nil, errors.New("obi: first argument incorrect map") + } + } else if s, ok := args[0].(string); ok { + pos, err := obiutils.InterfaceToInt(args[1]) + if err != nil { + return nil, err + } + return string(s[pos]), nil + } + return nil, fmt.Errorf("invalid arguments") + }), gval.Function("gc", func(args ...interface{}) (interface{}, error) { composition := (args[0].(*BioSequence)).Composition() - return float64(composition['g']+composition['c']) / float64(args[0].(*BioSequence).Len()), nil + return float64(composition['g']+composition['c']) / float64(args[0].(*BioSequence).Len()-composition['o']), nil }), gval.Function("composition", func(args ...interface{}) (interface{}, error) { comp := (args[0].(*BioSequence)).Composition() - scomp := make(map[string]float64) + scomp := make(map[string]interface{}, 5) for k, v := range comp { scomp[string(k)] = float64(v) } @@ -209,4 +257,22 @@ var OBILang = gval.NewLanguage( results := pattern.ReplaceAllString(args[0].(string), args[2].(string)) return results, nil }), + gval.Function("substr", func(args ...interface{}) (interface{}, error) { + str, ok1 := args[0].(string) + start, ok2 := args[1].(float64) // Gval utilise float64 pour les nombres + length, ok3 := args[2].(float64) + + if !ok1 || !ok2 || !ok3 { + return nil, fmt.Errorf("invalid arguments") + } + + startIndex := int(start) + endIndex := startIndex + int(length) + + if startIndex < 0 || endIndex > len(str) { + return nil, fmt.Errorf("index out of range") + } + + return str[startIndex:endIndex], nil + }), ) diff --git a/pkg/obiutils/cast_interface.go b/pkg/obiutils/cast_interface.go index f56c55a..7184f45 100644 --- a/pkg/obiutils/cast_interface.go +++ b/pkg/obiutils/cast_interface.go @@ -4,6 +4,7 @@ import ( "fmt" "reflect" "strconv" + "strings" log "github.com/sirupsen/logrus" ) @@ -14,7 +15,12 @@ import ( // It returns the string representation and an error if any occurred during the conversion process. func InterfaceToString(i interface{}) (val string, err error) { err = nil - val = fmt.Sprintf("%v", i) + if vc, ok := i.(interface{ String() string }); ok { + val = vc.String() + } else { + val = fmt.Sprintf("%v", i) + } + return } @@ -67,6 +73,10 @@ func InterfaceToBool(i interface{}) (val bool, err error) { val = t != 0 // standardizes across systems case uint64: val = t != 0 // standardizes across systems + case string: + val = strings.ToLower(t) == "true" || t == "1" || strings.ToLower(t) == "yes" || strings.ToLower(t) == "on" || strings.ToLower(t) == "t" + case nil: + val = false default: err = &NotABoolean{"value attribute cannot be casted to a boolean"} }