enotype 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 49b45ee141f7108c88785143cbae350f76dee9dbb6d5dd1acbce7972bc3bbfe6
4
+ data.tar.gz: 5e3f2de9a97da96a79757a56d2c3be830b3f3ccec01c7392fd437a4bf26fdad6
5
+ SHA512:
6
+ metadata.gz: 8cc784fcf21d0d73ade3cd036288b953d40f32fe4a8394cbfb92f10610c052b10fa9ce2997d4237b97e9fec9cf09751bf0ace0464851dab3cd0a634bda24d362
7
+ data.tar.gz: 57d00f2f5c740134ccfbea7b125ab0ea335795bb0d0b2f9b9e200f2bb60d34494abc11feda7c0caeedf9b23ba4dd37f47faf4e5487d11dd4ffa7ea54e6a2da08
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2019 Simon Repp
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,14 @@
1
+ # enotype
2
+
3
+ **A cross-language standard library for types.**
4
+
5
+ ```ruby
6
+ require 'enotype'
7
+
8
+ Enotype::color('#fff') # returns '#fff'
9
+ Enotype::color('#xyz') # raises 'A color is required, for instance '#B6D918', '#fff' or '#01b'.'
10
+ ```
11
+
12
+ enotype is a collection of minimalist pure functions that validate and convert type-unsafe `string` representations into type-safe, native types.
13
+
14
+ It is the standard type library for the [eno notation language](https://eno-lang.org) but can be utilized in a multitude of other contexts as well.
@@ -0,0 +1 @@
1
+ require 'enotype/en'
@@ -0,0 +1,103 @@
1
+ require 'json'
2
+
3
+ COLOR_REGEXP = /^\s*#[0-9a-f]{3}([0-9a-f]{3})?\s*$/i
4
+ DATE_REGEXP = /^\s*(\d{4})-(\d\d)-(\d\d)\s*$/
5
+ DATETIME_REGEXP = /^\s*(\d{4})(?:-(\d\d)(?:-(\d\d)(?:T(\d\d):(\d\d)(?::(\d\d)(?:\.(\d+))?)?(?:(Z)|([+\-])(\d\d):(\d\d)))?)?)?\s*$/
6
+ EMAIL_REGEXP = /^\s*[^@\s]+@[^@\s]+\.[^@\s]+\s*$/
7
+ FLOAT_REGEXP = /^\s*-?\d+(\.\d+)?\s*$/
8
+ INTEGER_REGEXP = /^\s*-?\d+\s*$/
9
+ LAT_LNG_REGEXP = /^\s*(-?\d{1,3}(?:\.\d+)?)\s*,\s*(-?\d{1,3}(?:\.\d+)?)\s*$/
10
+ URL_REGEXP = /^\s*https?:\/\/[^\s.]+\.\S+\s*$/
11
+
12
+ module Enotype
13
+ def self.boolean(value)
14
+ lower = value.strip.downcase
15
+
16
+ return true if lower == 'true'
17
+ return false if lower == 'false'
18
+ return true if lower == 'yes'
19
+ return false if lower == 'no'
20
+
21
+ raise 'Ein boolescher Wert ist erforderlich - erlaubte Werte sind \'true\', \'false\', \'yes\' und \'no\'.'
22
+ end
23
+
24
+ def self.color(value)
25
+ raise 'Eine Farbe ist erforderlich, zum Beispiel \'#B6D918\', \'#fff\' oder \'#01b\'.' unless value.match(COLOR_REGEXP)
26
+
27
+ value
28
+ end
29
+
30
+ def self.comma_separated(value)
31
+ value.split(',', -1).map { |item| item.strip }
32
+ end
33
+
34
+ def self.date(value)
35
+ match = value.match(DATE_REGEXP)
36
+
37
+ raise 'Ein valides Datum ist erforderlich, zum Beispiel \'1993-11-18\'.' unless match
38
+
39
+ year = match[1].to_i
40
+ month = match[2].to_i
41
+ day = match[3].to_i
42
+
43
+ Time.utc(year, month, day)
44
+ end
45
+
46
+ def self.datetime(value)
47
+ match = value.match(DATETIME_REGEXP)
48
+
49
+ raise 'Ein valides Datum oder Datum und Zeit sind erforderlich, zum Beispiel \'1961-01-22\' oder \'1989-11-09T19:17Z\' (siehe https://www.w3.org/TR/NOTE-datetime).' unless match
50
+
51
+ year = match[1].to_i
52
+ month = match[2] ? match[2].to_i : 1
53
+ day = match[3] ? match[3].to_i : 1
54
+ hour = match[4] ? match[4].to_i : 0
55
+ minute = match[5] ? match[5].to_i : 0
56
+ second = match[6] ? match[6].to_i : 0
57
+ fraction = match[7] ? "0.#{match[7]}".to_f : 0
58
+ zulu = match[8]
59
+ offset = zulu ? '+00:00' : "#{match[9] || '+'}#{match[10] || '00'}:#{match[11] || '00'}"
60
+
61
+ Time.new(year, month, day, hour, minute, second + fraction, offset)
62
+ end
63
+
64
+ def self.email(value)
65
+ raise 'Eine valide Email Adresse ist erforderlich, zum Beispiel \'jane.doe@eno-lang.org\'.' unless value.match(EMAIL_REGEXP)
66
+
67
+ value
68
+ end
69
+
70
+ def self.float(value)
71
+ raise 'Eine Dezimalzahl ist erforderlich, zum Beispiel \'13.0\', \'-9.159\' oder \'42\'.' unless value.match(FLOAT_REGEXP)
72
+
73
+ value.to_f
74
+ end
75
+
76
+ def self.integer(value)
77
+ raise 'Eine Ganzzahl ist erforderlich, zum Beispiel \'42\' oder \'-21\'.' unless value.match(INTEGER_REGEXP)
78
+
79
+ value.to_i
80
+ end
81
+
82
+ def self.json(value)
83
+ begin
84
+ JSON.parse(value)
85
+ rescue => err
86
+ raise "Valides JSON ist erforderlich - die Meldung des Parsers war:\n#{err.message}"
87
+ end
88
+ end
89
+
90
+ def self.lat_lng(value)
91
+ match = LAT_LNG_REGEXP.match(value)
92
+
93
+ raise 'Ein valides Breiten-/Längengrad Koordinatenpaar ist erforderlich, zum Beispiel \'48.2093723, 16.356099\'.' unless match
94
+
95
+ { lat: match[1].to_f, lng: match[2].to_f }
96
+ end
97
+
98
+ def self.url(value)
99
+ raise 'Eine valide URL ist erforderlich, zum Beispiel \'https://eno-lang.org\'.' unless value.match(URL_REGEXP)
100
+
101
+ value
102
+ end
103
+ end
@@ -0,0 +1,103 @@
1
+ require 'json'
2
+
3
+ COLOR_REGEXP = /^\s*#[0-9a-f]{3}([0-9a-f]{3})?\s*$/i
4
+ DATE_REGEXP = /^\s*(\d{4})-(\d\d)-(\d\d)\s*$/
5
+ DATETIME_REGEXP = /^\s*(\d{4})(?:-(\d\d)(?:-(\d\d)(?:T(\d\d):(\d\d)(?::(\d\d)(?:\.(\d+))?)?(?:(Z)|([+\-])(\d\d):(\d\d)))?)?)?\s*$/
6
+ EMAIL_REGEXP = /^\s*[^@\s]+@[^@\s]+\.[^@\s]+\s*$/
7
+ FLOAT_REGEXP = /^\s*-?\d+(\.\d+)?\s*$/
8
+ INTEGER_REGEXP = /^\s*-?\d+\s*$/
9
+ LAT_LNG_REGEXP = /^\s*(-?\d{1,3}(?:\.\d+)?)\s*,\s*(-?\d{1,3}(?:\.\d+)?)\s*$/
10
+ URL_REGEXP = /^\s*https?:\/\/[^\s.]+\.\S+\s*$/
11
+
12
+ module Enotype
13
+ def self.boolean(value)
14
+ lower = value.strip.downcase
15
+
16
+ return true if lower == 'true'
17
+ return false if lower == 'false'
18
+ return true if lower == 'yes'
19
+ return false if lower == 'no'
20
+
21
+ raise 'A boolean is required - allowed values are \'true\', \'false\', \'yes\' and \'no\'.'
22
+ end
23
+
24
+ def self.color(value)
25
+ raise 'A color is required, for instance \'#B6D918\', \'#fff\' or \'#01b\'.' unless value.match(COLOR_REGEXP)
26
+
27
+ value
28
+ end
29
+
30
+ def self.comma_separated(value)
31
+ value.split(',', -1).map { |item| item.strip }
32
+ end
33
+
34
+ def self.date(value)
35
+ match = value.match(DATE_REGEXP)
36
+
37
+ raise 'A valid date is required, for instance \'1993-11-18\'.' unless match
38
+
39
+ year = match[1].to_i
40
+ month = match[2].to_i
41
+ day = match[3].to_i
42
+
43
+ Time.utc(year, month, day)
44
+ end
45
+
46
+ def self.datetime(value)
47
+ match = value.match(DATETIME_REGEXP)
48
+
49
+ raise 'A valid date or date and time are required, for instance \'1961-01-22\' or \'1989-11-09T19:17Z\' (see https://www.w3.org/TR/NOTE-datetime).' unless match
50
+
51
+ year = match[1].to_i
52
+ month = match[2] ? match[2].to_i : 1
53
+ day = match[3] ? match[3].to_i : 1
54
+ hour = match[4] ? match[4].to_i : 0
55
+ minute = match[5] ? match[5].to_i : 0
56
+ second = match[6] ? match[6].to_i : 0
57
+ fraction = match[7] ? "0.#{match[7]}".to_f : 0
58
+ zulu = match[8]
59
+ offset = zulu ? '+00:00' : "#{match[9] || '+'}#{match[10] || '00'}:#{match[11] || '00'}"
60
+
61
+ Time.new(year, month, day, hour, minute, second + fraction, offset)
62
+ end
63
+
64
+ def self.email(value)
65
+ raise 'A valid email address is required, for instance \'jane.doe@eno-lang.org\'.' unless value.match(EMAIL_REGEXP)
66
+
67
+ value
68
+ end
69
+
70
+ def self.float(value)
71
+ raise 'A decimal number is required, for instance \'13.0\', \'-9.159\' or \'42\'.' unless value.match(FLOAT_REGEXP)
72
+
73
+ value.to_f
74
+ end
75
+
76
+ def self.integer(value)
77
+ raise 'An integer is required, for instance \'42\' or \'-21\'.' unless value.match(INTEGER_REGEXP)
78
+
79
+ value.to_i
80
+ end
81
+
82
+ def self.json(value)
83
+ begin
84
+ JSON.parse(value)
85
+ rescue => err
86
+ raise "Valid JSON is required - the parser returned:\n#{err.message}"
87
+ end
88
+ end
89
+
90
+ def self.lat_lng(value)
91
+ match = LAT_LNG_REGEXP.match(value)
92
+
93
+ raise 'A valid latitude/longitude coordinate pair is required, for instance \'48.2093723, 16.356099\'.' unless match
94
+
95
+ { lat: match[1].to_f, lng: match[2].to_f }
96
+ end
97
+
98
+ def self.url(value)
99
+ raise 'A valid URL is required, for instance \'https://eno-lang.org\'.' unless value.match(URL_REGEXP)
100
+
101
+ value
102
+ end
103
+ end
@@ -0,0 +1,103 @@
1
+ require 'json'
2
+
3
+ COLOR_REGEXP = /^\s*#[0-9a-f]{3}([0-9a-f]{3})?\s*$/i
4
+ DATE_REGEXP = /^\s*(\d{4})-(\d\d)-(\d\d)\s*$/
5
+ DATETIME_REGEXP = /^\s*(\d{4})(?:-(\d\d)(?:-(\d\d)(?:T(\d\d):(\d\d)(?::(\d\d)(?:\.(\d+))?)?(?:(Z)|([+\-])(\d\d):(\d\d)))?)?)?\s*$/
6
+ EMAIL_REGEXP = /^\s*[^@\s]+@[^@\s]+\.[^@\s]+\s*$/
7
+ FLOAT_REGEXP = /^\s*-?\d+(\.\d+)?\s*$/
8
+ INTEGER_REGEXP = /^\s*-?\d+\s*$/
9
+ LAT_LNG_REGEXP = /^\s*(-?\d{1,3}(?:\.\d+)?)\s*,\s*(-?\d{1,3}(?:\.\d+)?)\s*$/
10
+ URL_REGEXP = /^\s*https?:\/\/[^\s.]+\.\S+\s*$/
11
+
12
+ module Enotype
13
+ def self.boolean(value)
14
+ lower = value.strip.downcase
15
+
16
+ return true if lower == 'true'
17
+ return false if lower == 'false'
18
+ return true if lower == 'yes'
19
+ return false if lower == 'no'
20
+
21
+ raise 'Se requiere un valor booleano - valores permitidos son \'true\', \'false\', \'yes\' y \'no\'.'
22
+ end
23
+
24
+ def self.color(value)
25
+ raise 'Se requiere un color, por ejemplo \'#B6D918\', \'#fff\' o \'#01b\'.' unless value.match(COLOR_REGEXP)
26
+
27
+ value
28
+ end
29
+
30
+ def self.comma_separated(value)
31
+ value.split(',', -1).map { |item| item.strip }
32
+ end
33
+
34
+ def self.date(value)
35
+ match = value.match(DATE_REGEXP)
36
+
37
+ raise 'Se requiere una fecha valida, por ejemplo \'1993-11-18\'' unless match
38
+
39
+ year = match[1].to_i
40
+ month = match[2].to_i
41
+ day = match[3].to_i
42
+
43
+ Time.utc(year, month, day)
44
+ end
45
+
46
+ def self.datetime(value)
47
+ match = value.match(DATETIME_REGEXP)
48
+
49
+ raise 'Se requiere una valida fecha o fecha y hora, por ejemplo \'1961-01-22\' o \'1989-11-09T19:17Z\' (vea https://www.w3.org/TR/NOTE-datetime).' unless match
50
+
51
+ year = match[1].to_i
52
+ month = match[2] ? match[2].to_i : 1
53
+ day = match[3] ? match[3].to_i : 1
54
+ hour = match[4] ? match[4].to_i : 0
55
+ minute = match[5] ? match[5].to_i : 0
56
+ second = match[6] ? match[6].to_i : 0
57
+ fraction = match[7] ? "0.#{match[7]}".to_f : 0
58
+ zulu = match[8]
59
+ offset = zulu ? '+00:00' : "#{match[9] || '+'}#{match[10] || '00'}:#{match[11] || '00'}"
60
+
61
+ Time.new(year, month, day, hour, minute, second + fraction, offset)
62
+ end
63
+
64
+ def self.email(value)
65
+ raise 'Se requiere una dirección electrónica valida, por ejemplo \'jane.doe@eno-lang.org\'.' unless value.match(EMAIL_REGEXP)
66
+
67
+ value
68
+ end
69
+
70
+ def self.float(value)
71
+ raise 'Se requiere un número decimal, por ejemplo \'13.0\', \'-9.159\' o \'42\'.' unless value.match(FLOAT_REGEXP)
72
+
73
+ value.to_f
74
+ end
75
+
76
+ def self.integer(value)
77
+ raise 'Se requiere un número entero, por ejemplo \'42\' o \'-21\'.' unless value.match(INTEGER_REGEXP)
78
+
79
+ value.to_i
80
+ end
81
+
82
+ def self.json(value)
83
+ begin
84
+ JSON.parse(value)
85
+ rescue => err
86
+ raise "Se requiere JSON valido - el mensaje del parser fue:\n#{err.message}"
87
+ end
88
+ end
89
+
90
+ def self.lat_lng(value)
91
+ match = LAT_LNG_REGEXP.match(value)
92
+
93
+ raise 'Se requiere una pareja de coordenadas latitud/longitud valida, por ejemplo \'48.2093723, 16.356099\'' unless match
94
+
95
+ { lat: match[1].to_f, lng: match[2].to_f }
96
+ end
97
+
98
+ def self.url(value)
99
+ raise 'Se requiere un URL valido, por ejemplo \'https://eno-lang.org\'.' unless value.match(URL_REGEXP)
100
+
101
+ value
102
+ end
103
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: enotype
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Simon Repp
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-02-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.8'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.8'
27
+ description: enotype is a collection of minimalist pure functions that validate and
28
+ convert type-unsafe string representations into type-safe, native types.
29
+ email: simon@fdpl.io
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - LICENSE.txt
35
+ - README.md
36
+ - lib/enotype.rb
37
+ - lib/enotype/de.rb
38
+ - lib/enotype/en.rb
39
+ - lib/enotype/es.rb
40
+ homepage: https://eno-lang.org/
41
+ licenses:
42
+ - MIT
43
+ metadata: {}
44
+ post_install_message:
45
+ rdoc_options: []
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 2.3.0
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ requirements: []
59
+ rubyforge_project:
60
+ rubygems_version: 2.7.8
61
+ signing_key:
62
+ specification_version: 4
63
+ summary: A cross-language standard library for types
64
+ test_files: []