msfl 1.1.6 → 1.2.0.dev

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9034a3e616954189429dc66d76be624f065b5f9b
4
- data.tar.gz: 8ef828b22da3158dc126e3d8ae8a148bdf82f9b9
3
+ metadata.gz: 836568a1640ce165512978aa087ea16d8c87088e
4
+ data.tar.gz: d5898063d32d174b84522ab16a56265b4453b9a8
5
5
  SHA512:
6
- metadata.gz: fe03bb90fc8cd612c5914217600a02dfb3a8fd4a5e08e6f701b5e80cdb704f8128e8335c245300d7a2ed6ad2d45b051ac804b496b7386f7350f3484aecf0975d
7
- data.tar.gz: 920a0e38dbf3256d45695c60dced75252ddff4d8cf7babaa63825da13b72fb36c220dc13f08ccf364474b0478eb888c7854d01479b39c5e5562865b71ec24fc5
6
+ metadata.gz: 5df4af19fc17ababf06c3570af87f93021d6ff4dc7bfedf936dfe9942f3e4016d15e6eb5a8b4f73bb38292996ff173b36263eff1d0e24fe78a1f376f5662fcb2
7
+ data.tar.gz: ded9b1ceae6f7806502a2f8a3e0c5c3e5c19968c3a5dec9fac35e3d0f1ff7fe9eab8857feb13ae1ce92764ad085335a1ee16987861a60b2dc4a1172e5330eee6
data/README.md CHANGED
@@ -1,5 +1,18 @@
1
1
  [![Circle CI](https://circleci.com/gh/Referly/msfl.svg?style=svg)](https://circleci.com/gh/Referly/msfl)
2
2
 
3
+ # MSFL
4
+
5
+ The Mattermark Semantic Filter Language is a language for _filtering_ data. It allows users to construct filters
6
+ on sets of data in a Venn diagram like fashion. More formally it allows the user to create subsets of data.
7
+
8
+ MSFL is different than other languages - it is _not_ a query language. It has no notion of concepts like _order_,
9
+ _limit_, _offset_, _group_by_, or _having_.
10
+
11
+ It does support faceted filtering through a vocabulary added in 1.2 which allows the user to define filters
12
+ on the hyperset of the data. (In the non-hyper case all of the extra dimensions are simplified to constants.) If
13
+ you don't know what faceted filtering is or this sounds overwhelming, just ignore this bit. When you get to the point
14
+ that you need faceted filtering in your application then this will seem second nature.
15
+
3
16
  # Ruby Gem for the Mattermark Semantic Filter Language
4
17
 
5
18
  Contains serializers and validators (and perhaps other) MSFL goodies
@@ -8,27 +21,191 @@ Contains serializers and validators (and perhaps other) MSFL goodies
8
21
 
9
22
  MSFL is a context-free language. The context-free grammar is defined below.
10
23
 
11
- I'm not actually sure this is correct, it is definitely not comprehensive as it skips over the shortcut functionality.
24
+ # EXPRESSIONS
25
+
26
+ filter = lc , { filter_expr } , rc ;
27
+
28
+ filter_expr = range_expr
29
+ | binary_expr
30
+ | set_expr
31
+ | partial_expr
32
+ | foreign_expr ;
33
+
34
+ range_expr = between ;
35
+
36
+ binary_expr = comparisons
37
+ | containment ;
38
+
39
+ set_expr = and
40
+ | or ;
41
+
42
+ partial_expr = partial_op , colon , partial ;
43
+
44
+ foreign_expr = word , colon , filter ;
45
+
46
+ partial = lc , given_expr , comma , partial_filter , rc ;
47
+
48
+ given_expr = given_op , colon, filter ;
49
+
50
+ partial_filter = filter_op , colon , filter ;
51
+
52
+ between = value , colon , start_end
53
+ | value , colon , between_body ;
54
+
55
+ comparisons = comparison , { comma , comparison } ;
56
+
57
+ containment = word , colon , in_expr ;
58
+
59
+ and = and_op , colon , filters ;
60
+
61
+ or = or_op , colon , filters ;
62
+
63
+ comparison = word , colon , value
64
+ | word , colon , lc , comparison_list , rc ;
65
+
66
+ comparison_list = comparison_expr , { comma , comparison_expr } ;
67
+
68
+ comparison_expr = comparison_op , colon , value ;
69
+
70
+ in_expr = lc , in_op , colon , values , rc ;
71
+
72
+ filters = ls , { filter } , rs ;
73
+
74
+ values = ls , { value } , rs ;
75
+
76
+ between_body = lc , between_op , colon , start_end , rc ;
77
+
78
+ start_end = lc , start_expr , comma , end_expr , rc ;
79
+
80
+ start_expr = start_op , colon , range_value ;
81
+
82
+ end_expr = end_op , colon , range_value ;
83
+
84
+
85
+
86
+ # OPERATORS
87
+
88
+ partial_op = dq , "partial" , dq ;
89
+
90
+ given_op = dq , "given" , dq ;
91
+
92
+ filter_op = dq , "filter" , dq ;
93
+
94
+ in_op = dq , "in" , dq ;
95
+
96
+ between_op = dq , "between" , dq ;
97
+
98
+ start_op = dq , "start" , dq ;
99
+
100
+ end_op = dq , "end" , dq ;
101
+
102
+ comparison_op = lt_op
103
+ | gt_op
104
+ | lte_op
105
+ | gte_op
106
+ | eq_op ;
107
+
108
+ lt_op = dq , "lt" , dq ;
109
+
110
+ gt_op = dq , "gt" , dq ;
111
+
112
+ lte_op = dq , "lte" , dq ;
113
+
114
+ gte_op = dq , "gte" , dq ;
115
+
116
+ eq_op = dq , "eq" , dq ;
117
+
118
+ and_op = dq , "and" , dq ;
119
+
120
+ or_op = dq , "or" , dq ;
121
+
122
+
123
+
124
+ # VALUES AND TYPES
125
+
126
+ range_value = number
127
+ | date
128
+ | datetime
129
+ | time ;
130
+
131
+ value = word
132
+ | range_value
133
+ | boolean ;
134
+
135
+ word = dq , character , { character } , dq ;
136
+
137
+ number = integer | decimal ;
138
+
139
+ integer = [ hyphen ] , digit , { digit } ;
140
+
141
+ decimal = integer
142
+ | { integer } , dot , { digit } ;
143
+
144
+ boolean = true | false ;
145
+
146
+ true = "true"
147
+ | dq , "true" , dq
148
+ | "1"
149
+ | dq , "1" , dq ;
150
+
151
+ false = "false"
152
+ | dq , "false" , dq
153
+ | "0"
154
+ | dq , "0" , dq ;
155
+
156
+ date = ? ISO 8601 date format http://en.wikipedia.org/wiki/ISO_8601 ? ;
157
+
158
+ datetime = ? ISO 8601 combined date and time format http://en.wikipedia.org/wiki/ISO_8601 ? ;
159
+
160
+ time = ? ISO 8601 time format http://en.wikipedia.org/wiki/ISO_8601 ? ;
161
+
162
+ character = letter
163
+ | digit
164
+ | symbol ;
165
+
166
+ letter = "A" | "B" | "C" | "D" | "E" | "F" | "G"
167
+ | "H" | "I" | "J" | "K" | "L" | "M" | "N"
168
+ | "O" | "P" | "Q" | "R" | "S" | "T" | "U"
169
+ | "V" | "W" | "X" | "Y" | "Z"
170
+ | "a" | "b" | "c" | "d" | "e" | "f" | "g"
171
+ | "h" | "i" | "j" | "k" | "l" | "m" | "n"
172
+ | "o" | "p" | "q" | "r" | "s" | "t" | "u"
173
+ | "v" | "w" | "x" | "y" | "z" ;
174
+
175
+ digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
176
+
177
+ symbol = "'" | "~" | "." | "_" | "-" | ":" | "?" | "/" | "=" | "@" | "&" ;
178
+
179
+ left_curly = "{" ;
180
+
181
+ lc = left_curly ;
182
+
183
+ right_curly = "}" ;
184
+
185
+ rc = right_curly ;
186
+
187
+ left_square = "[" ;
188
+
189
+ ls = left_square ;
190
+
191
+ right_square = "]" ;
192
+
193
+ rs = right_square ;
194
+
195
+ comma = "," ;
196
+
197
+ hyphen = "-" ;
198
+
199
+ colon = ":" ;
200
+
201
+ double_quote = '"' ;
202
+
203
+ dq = double_quote ;
204
+
205
+ dot = "." ;
206
+
207
+
12
208
 
13
- ```
14
- filter = range_op | binary_op | set_op
15
- set_op = and | or
16
- and = "{" "\"and\"" ":" list "}"
17
- or = "{" "\"or\"" ":" list "}"
18
- list = "[" filter? | (filter ("," filter)*) "]";
19
- range_op = between;
20
- between = "{" field ":" between_body | "{" "\"between\"" ":" between_body "}";
21
- between_body = "{" "\"start\"" ":" between_start "," "\"end\"" ":" between_end "}";
22
- between_start = integer | double | date | datetime | time;
23
- between_end = integer | double | date | datetime | time;
24
- binary_op = comparison | containment;
25
- comparison = "{" field ":" "{" comparison_op ":" atom "}" "}";
26
- field = "\"" ALPHANUMERIC+ "\"";
27
- comparison_op = "lt" | "gt" | "lte" | "gte" | "eq";
28
- containment = "{" field ":" "{" "\"in\"" ":" atom_list "}" "}";
29
- atom = string | integer | double | boolean | date | datetime | time;
30
- atom_list = "[" atom? | (atom ("," atom)*) "]";
31
- ```
32
209
 
33
210
  ## Configuration
34
211
 
@@ -69,6 +246,14 @@ After parsing a MSFL filter it can be validated. Currently the validation is pri
69
246
  semantic validation on a per dataset basis. This will allow per attribute validations to be setup by the consumer
70
247
  of this gem, which will be run automatically during validation.
71
248
 
249
+ Validation works in the following order
250
+
251
+ 1. Grammar validation
252
+
253
+ 2. Dataset configured validation
254
+
255
+ 3. Dataset semantic validation
256
+
72
257
  ## Frameworks
73
258
 
74
259
  ### Sinatra
@@ -8,7 +8,7 @@ module MSFL
8
8
  register_dataset
9
9
 
10
10
  def fields
11
- [:make, :model, :year, :value]
11
+ [:make, :model, :year, :value, :owner]
12
12
  end
13
13
  end
14
14
  end
@@ -0,0 +1,15 @@
1
+ require_relative 'base'
2
+
3
+ module MSFL
4
+ module Datasets
5
+ # This is a fake dataset definition that shows the structure for composing your own and is used for testing
6
+ # msfl
7
+ class Person < ::MSFL::Datasets::Base
8
+ register_dataset
9
+
10
+ def fields
11
+ [:name, :gender, :age, :cars]
12
+ end
13
+ end
14
+ end
15
+ end
@@ -16,7 +16,7 @@ module MSFL
16
16
  obj
17
17
  end
18
18
 
19
- # Converts Ruby Arrays is a partially parsed Ruby MSFL filter to MSFL::Types::Set objects
19
+ # Converts Ruby Arrays in a partially parsed Ruby MSFL filter to MSFL::Types::Set objects
20
20
  #
21
21
  # @param obj [Object] the object in which to convert Ruby Array objects to MSFL::Types::Set objects
22
22
  # @return [Object] the result of converting Ruby Arrays to MSFL::Types::Set objects
data/msfl.gemspec CHANGED
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'msfl'
3
- s.version = '1.1.6'
4
- s.date = '2015-04-01'
3
+ s.version = '1.2.0.dev'
4
+ s.date = '2015-05-12'
5
5
  s.summary = "MSFL in Ruby"
6
6
  s.description = "Serializers, validators, and other tasty goodness for the Mattermark Semantic Filter Language in Ruby."
7
7
  s.authors = ["Courtland Caldwell"]
@@ -34,6 +34,27 @@ describe "MSFL::Parsers::JSON" do
34
34
  it { is_expected.to be_a MSFL::Types::Set }
35
35
  end
36
36
 
37
+ context "when parsing a foreign" do
38
+
39
+ # The test scenario here is if we are limiting the set of cars by person criteria (only cars owned by people over 25)
40
+
41
+ let(:test_json) { '{"person":{"age":{"gte":25}}}' }
42
+
43
+ it "is an equivalent Ruby hash" do
44
+ expect(mut).to eq({ person: { age: { gte: 25 } } })
45
+ end
46
+
47
+ end
48
+
49
+ context "when parsing a partial" do
50
+
51
+ let(:test_json) { '{"partial":{"given":{"make":"Toyota"},"filter":{"avg_age":10}}}'}
52
+
53
+ it "is an equivalent Ruby Hash" do
54
+ expect(mut).to eq({ partial: { given: { make: "Toyota" }, filter: { avg_age: 10 } } })
55
+ end
56
+ end
57
+
37
58
  end
38
59
 
39
60
  describe ".arrays_to_sets" do
metadata CHANGED
@@ -1,97 +1,97 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: msfl
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.6
4
+ version: 1.2.0.dev
5
5
  platform: ruby
6
6
  authors:
7
7
  - Courtland Caldwell
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-01 00:00:00.000000000 Z
11
+ date: 2015-05-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '1.7'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.7'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
33
  version: '10.3'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '10.3'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: simplecov
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ~>
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0.9'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ~>
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0.9'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: yard
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ~>
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0.8'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ~>
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0.8'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rspec
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ~>
73
+ - - "~>"
74
74
  - !ruby/object:Gem::Version
75
75
  version: '3.1'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ~>
80
+ - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: '3.1'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: byebug
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ~>
87
+ - - "~>"
88
88
  - !ruby/object:Gem::Version
89
89
  version: '3.5'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - ~>
94
+ - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '3.5'
97
97
  description: Serializers, validators, and other tasty goodness for the Mattermark
@@ -101,7 +101,7 @@ executables: []
101
101
  extensions: []
102
102
  extra_rdoc_files: []
103
103
  files:
104
- - .gitignore
104
+ - ".gitignore"
105
105
  - Gemfile
106
106
  - Gemfile.lock
107
107
  - LICENSE
@@ -116,6 +116,7 @@ files:
116
116
  - lib/msfl/datasets/base.rb
117
117
  - lib/msfl/datasets/car.rb
118
118
  - lib/msfl/datasets/movie.rb
119
+ - lib/msfl/datasets/person.rb
119
120
  - lib/msfl/parsers.rb
120
121
  - lib/msfl/parsers/json.rb
121
122
  - lib/msfl/sinatra.rb
@@ -146,17 +147,17 @@ require_paths:
146
147
  - lib
147
148
  required_ruby_version: !ruby/object:Gem::Requirement
148
149
  requirements:
149
- - - '>='
150
+ - - ">="
150
151
  - !ruby/object:Gem::Version
151
152
  version: '0'
152
153
  required_rubygems_version: !ruby/object:Gem::Requirement
153
154
  requirements:
154
- - - '>='
155
+ - - ">"
155
156
  - !ruby/object:Gem::Version
156
- version: '0'
157
+ version: 1.3.1
157
158
  requirements: []
158
159
  rubyforge_project:
159
- rubygems_version: 2.4.2
160
+ rubygems_version: 2.2.2
160
161
  signing_key:
161
162
  specification_version: 4
162
163
  summary: MSFL in Ruby