msfl 0.0.1.pre.rc1 → 0.0.1.pre.rc2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1433fb3fe0766b9a5a4913a5c8236bffb00e9c5e
4
- data.tar.gz: 9307024455e4e75530f334e4c91d2a09f7da7090
3
+ metadata.gz: daafbe97f5c20cfcd8c01f85f037d2ce541f79ea
4
+ data.tar.gz: 5dc889069b814f410425cd899a195affb0d5033e
5
5
  SHA512:
6
- metadata.gz: 1a7ac56dec38d01c8dcec0521e27cb03f361d952d8309d72bfa6494e9b5b49c8e34a89d1f2e98c66742a885110519ecd41ea24d3aa05b2508b1eeb20155244e3
7
- data.tar.gz: 8a8150eb7c2ded7f183e7f124167a2dd3de92477cdc52731ee6868599625b344308c80bb5707230e51847ba11ad6a0635129a69a77887b112d570ffc3c2df6b5
6
+ metadata.gz: 82a657a00b0dfa31b645d4a23bf587768510dd03dbeaa659543e11570af810688e29dad84475c4632ef1dc0c7f9f1b2c3115af9f6579f764b9d99be54268c8e5
7
+ data.tar.gz: be3361401722d576c5a9cb66dd1f4c4883f1d9abdf9328fe52f7dce1966deb09ffe7b16cebe4d21496847b23cf9642465c3f018196da031439c4726c1c63258d
data/lib/msfl.rb CHANGED
@@ -3,6 +3,7 @@ require 'msfl/types'
3
3
  require 'msfl/validators'
4
4
  require 'msfl/configuration'
5
5
  require 'msfl/datasets'
6
+ require 'msfl/sinatra'
6
7
 
7
8
  module MSFL
8
9
  class << self
@@ -4,6 +4,43 @@ module MSFL
4
4
 
5
5
  include Validators::Definitions::HashKey
6
6
 
7
+ # This class singleton code and the register_dataset method are a cute nicety for conveniently registering
8
+ # new datasets from within the datasets themselves
9
+ class << self
10
+ def registered_datasets
11
+ @registered_datasets ||= {}
12
+ end
13
+
14
+ def registered_datasets=(registered_datasets)
15
+ @registered_datasets = registered_datasets
16
+ end
17
+ end
18
+
19
+ # Register a MSFL::Dataset as a registered dataset so that other code can reference the dataset using its
20
+ # name as a symbol, instead of having to pass around the class name.
21
+ #
22
+ # If no arguments are provided it registers the current class and sets its name to the class name downcased
23
+ # The dataset being registered can be overridden. The dataset name (how one refers to the dataset as a symbol)
24
+ # can also be overridden.
25
+ #
26
+ # @todo add tests
27
+ #
28
+ # @meta-spinach
29
+ # @param dataset [Class] optionally specify a dataset to register (use this when registration occurs outside
30
+ # of a dataset's class scope)
31
+ # @param opts [Hash] options
32
+ # notable option: :name (it allows you to override the dataset name)
33
+ def self.register_dataset(dataset = nil, opts = {})
34
+ dataset ||= self
35
+ dataset_name = opts[:name] if opts.has_key?(:name)
36
+ dataset_name ||= dataset.name
37
+ dataset_name.slice! "MSFL::Datasets::"
38
+ dataset_name.downcase!
39
+ registered_datasets = MSFL::Datasets::Base.registered_datasets
40
+ registered_datasets[dataset_name.to_sym] = dataset
41
+ MSFL::Datasets::Base.registered_datasets = registered_datasets
42
+ end
43
+
7
44
  # The descendant class MUST override this method otherwise all field validations will fail
8
45
  #
9
46
  # The method defines an array of symbols, indicating what fields are supported for the Dataset
@@ -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 Cars < ::MSFL::Datasets::Base
8
+ register_dataset
9
+
10
+ def fields
11
+ [:make, :model, :year, :value]
12
+ end
13
+ end
14
+ end
15
+ end
@@ -5,6 +5,8 @@ module MSFL
5
5
  # This is a fake dataset definition that shows the structure for composing your own and is used for testing
6
6
  # msfl
7
7
  class Movies < ::MSFL::Datasets::Base
8
+ register_dataset
9
+
8
10
  def fields
9
11
  [:title, :rating, :description, :earnings]
10
12
  end
@@ -0,0 +1,90 @@
1
+ module MSFL
2
+ module Sinatra
3
+ class << self
4
+
5
+ attr_accessor :valid_filter
6
+
7
+ def valid_filter
8
+ @valid_filter ||= nil
9
+ end
10
+
11
+ # Extracts the filter clause from a Sinatra request params hash and parsers the filter
12
+ #
13
+ # @param params [Hash] the Sinatra request params
14
+ # @return [Object] the Ruby-ified MSFL filter
15
+ def parse_filter_from(params)
16
+ filter = params[:filter]
17
+ MSFL::Parsers::JSON.parse filter.to_json unless filter.nil?
18
+ end
19
+
20
+ # Extracts the dataset name from the Sinatra params. It then returns a new instance of the specified
21
+ # dataset.
22
+ #
23
+ # @param params [Hash] the Sinatra request params
24
+ # @return [MSFL::Datasets::Base, Nil] a new instance of the specified dataset, if it can be found, otherwise nil
25
+ def dataset_from(params)
26
+ dataset_name = params[:dataset].to_sym unless params[:dataset].nil?
27
+ dataset_name ||= nil
28
+ Datasets::Base.registered_datasets[dataset_name].new if Datasets::Base.registered_datasets.has_key?(dataset_name)
29
+ end
30
+
31
+ # Creates a semantic validator instance that is ready to validate the dataset
32
+ #
33
+ # @param params [Hash] the Sinatra request params
34
+ # @return [MSFL::Validators::Semantic] a validator instance ready to validate filters for the dataset
35
+ def validator_from(params)
36
+ MSFL::Validators::Semantic.new dataset_from(params)
37
+ end
38
+
39
+ # Validate the MSFL filter in the Sinatra request's params hash
40
+ #
41
+ # @param params [Hash] the Sinatra request params
42
+ # @return [Bool]
43
+ def validate(params)
44
+ validator = validator_from params
45
+ parsed_filter = parse_filter_from params
46
+ result = validator.validate parsed_filter
47
+ @valid_filter = parsed_filter if result
48
+ result
49
+ end
50
+ end
51
+
52
+ module Helpers
53
+ # This method extracts the dataset name and filter from the Sinatra params. It also performs semantic validation
54
+ # of the filter relative to the dataset.
55
+ #
56
+ # The method also has the side effect, when the filter is valid or setting the valid_filter singleton class
57
+ # instance variable valid_filter to the Ruby-ified parsed filter.
58
+ #
59
+ # @param params [Hash] this should be the params variable from the request context
60
+ # @return [Bool] returns true if the filter is valid, false otherwise.
61
+ def msfl_valid?(params)
62
+ Sinatra.validate params
63
+ end
64
+
65
+ # This method returns the valid MSFL filter. If the valid filter has already been extracted from the parameters
66
+ # it is returned, otherwise if the optional params argument is specified it will be sent to MSFL::Sinatra.validate
67
+ # and if the validation is successful the valid filter is returned. If the valid filter still cannot be determined
68
+ # then the method raises an ArgumentError.
69
+ #
70
+ # @param params [Hash] optionally pass in the Sinatra request parameters - this is intended to be used when no
71
+ # previously successful call to msfl_valid? has been made, so that when you just need the filter you can skip
72
+ # writing msfl_valid?(params) in your code.
73
+ # @return [Object] the Ruby-ified and validated MSFL filter
74
+ def msfl_filter(params = nil)
75
+ filter = Sinatra.valid_filter
76
+ if filter.nil?
77
+ Sinatra.validate params
78
+ filter = Sinatra.valid_filter
79
+ end
80
+ raise ArgumentError, "A valid filter could not be located in msfl_filter." if filter.nil?
81
+ filter
82
+ end
83
+ end
84
+
85
+ # Sinatra specific registration hook
86
+ def self.registered(app)
87
+ app.helpers Helpers if app.respond_to?(:helpers)
88
+ end
89
+ end
90
+ end
data/msfl.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'msfl'
3
- s.version = '0.0.1-rc1'
3
+ s.version = '0.0.1-rc2'
4
4
  s.date = '2015-03-05'
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."
@@ -0,0 +1,23 @@
1
+ shared_examples_for "an invocation of MSFL::Sinatra.validate" do
2
+
3
+ let(:params) { { dataset: dataset, filter: filter } }
4
+
5
+ context "when params[:dataset] is :movies" do
6
+
7
+ let(:dataset) { :movies }
8
+
9
+ context "when params[:filter] is a valid filter" do
10
+
11
+ let(:filter) { { title: "Gone with the wind" } }
12
+
13
+ it { is_expected.to be true }
14
+ end
15
+
16
+ context "when params[:filter] is an invalid filter" do
17
+
18
+ let(:filter) { { notavalidfield: "some arbitrary value" } }
19
+
20
+ it { is_expected.to be false }
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,98 @@
1
+ require 'spec_helper'
2
+
3
+ describe "MSFL::Sinatra::Helpers" do
4
+
5
+ let(:sinatra_app_class) do
6
+ klass = class SinatraTestAppClass
7
+ # In a proper Sinatra app there would be no need to this because when the extension is registered the helpers
8
+ # are automatically mixed in
9
+ include MSFL::Sinatra::Helpers
10
+ end
11
+ klass
12
+ end
13
+
14
+ let(:sinatra_app) { sinatra_app_class.new }
15
+
16
+ let(:params) { nil }
17
+
18
+ describe "#msfl_valid?" do
19
+
20
+ subject(:mut) { sinatra_app.msfl_valid? params }
21
+
22
+ it_behaves_like "an invocation of MSFL::Sinatra.validate"
23
+ end
24
+
25
+ describe "#msfl_filter" do
26
+
27
+ subject(:mut) { sinatra_app.msfl_filter params }
28
+
29
+ context "when Sinatra.valid_filter is a valid MSFL filter" do
30
+
31
+ let(:valid_filter) { { arbitrary: "hash" } }
32
+
33
+ before { MSFL::Sinatra.valid_filter = valid_filter }
34
+
35
+ it "is the valid MSFL filter" do
36
+ expect(mut).to eq valid_filter
37
+ end
38
+
39
+ end
40
+
41
+ context "when Sinatra.valid_filter is nil" do
42
+
43
+ before(:each) { MSFL::Sinatra.valid_filter = nil }
44
+
45
+ let(:params) { { filter: filter, dataset: dataset } }
46
+
47
+ let(:filter) { nil }
48
+
49
+ let(:dataset) { nil }
50
+
51
+ context "when params[:dataset] is nil" do
52
+
53
+ context "when params[:filter] is valid json" do
54
+
55
+ let(:filter) { { notavalidmsflkeybutokjson: ["a", "b"] } }
56
+
57
+ it "raises a NoMethodError" do
58
+ expect { mut }.to raise_error NoMethodError
59
+ end
60
+ end
61
+ end
62
+
63
+ context "when params[:filter] is not valid json" do
64
+
65
+ let(:filter) { "iamnotvalidjson" }
66
+
67
+ it "raises a JSON::ParserError" do
68
+ expect { mut }.to raise_error JSON::ParserError
69
+ end
70
+ end
71
+
72
+ context "when params[:filter] is nil" do
73
+
74
+ it "raises an ArgumentError" do
75
+ expect { mut }.to raise_error ArgumentError
76
+ end
77
+ end
78
+
79
+ context "when params[:dataset] is a valid Dataset" do
80
+
81
+ let(:dataset) { :cars }
82
+
83
+ context "when params[:filter] is a valid MSFL filter" do
84
+
85
+ let(:filter) { { make: { in: inner_array } } }
86
+
87
+ let(:inner_array) { ["Chevy", "Tesla"] }
88
+
89
+ let(:msfl_filter) { { make: { in: MSFL::Types::Set.new(inner_array) } } }
90
+
91
+ it "is the valid MSFL filter" do
92
+ expect(mut).to eq msfl_filter
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,97 @@
1
+ require 'spec_helper'
2
+
3
+
4
+ describe "MSFL::Sinatra" do
5
+
6
+ describe ".registered" do
7
+
8
+ let(:app) do
9
+ o = Object.new
10
+ allow(o).to receive :helpers
11
+ expect(o).to receive(:helpers).once
12
+ o
13
+ end
14
+
15
+ it "adds the methods in the Helpers module as helpers to a Sinatra application" do
16
+ MSFL::Sinatra.registered app
17
+ end
18
+ end
19
+
20
+ describe ".parse_filter_from" do
21
+
22
+ subject(:mut) { MSFL::Sinatra.parse_filter_from params }
23
+
24
+ let(:params) { { filter: filter } }
25
+
26
+ let(:filter) { nil }
27
+
28
+ context "when the params[:filter] is a hash" do
29
+
30
+ let(:filter) { { foo: inner_array } }
31
+
32
+ let(:inner_array) { ["cat", "dog"] }
33
+
34
+ let(:expected) { { foo: MSFL::Types::Set.new(inner_array) } }
35
+
36
+ it "is the MSFL parsed filter" do
37
+ expect(mut).to eq expected
38
+ end
39
+ end
40
+ end
41
+
42
+ describe ".dataset_from" do
43
+
44
+ subject(:mut) { MSFL::Sinatra.dataset_from params }
45
+
46
+ let(:params) { { dataset: dataset } }
47
+
48
+ let(:dataset) { nil }
49
+
50
+ context "when params[:dataset] is :movies" do
51
+
52
+ let(:dataset) { :movies }
53
+
54
+ it "is a new instance of MSFL::Datasets::Movies" do
55
+ expect(mut).to be_a MSFL::Datasets::Movies
56
+ end
57
+ end
58
+
59
+ context "when params[:dataset] is :cars" do
60
+
61
+ let(:dataset) { :cars }
62
+
63
+ it "is a new instance of MSFL::Datasets::Cars" do
64
+ expect(mut).to be_a MSFL::Datasets::Cars
65
+ end
66
+ end
67
+ end
68
+
69
+ describe ".validator_from" do
70
+
71
+ subject(:mut) { MSFL::Sinatra.validator_from params }
72
+
73
+ let(:params) { { dataset: dataset } }
74
+
75
+ let(:dataset) { nil }
76
+
77
+ context "when params[:dataset] is :movies" do
78
+
79
+ let(:dataset) { :movies }
80
+
81
+ it "is a semantic validator instance of MSFL::Datasets::Movies" do
82
+ validator = mut
83
+ expect(validator).to be_a MSFL::Validators::Semantic
84
+ expect(validator.dataset).to be_a MSFL::Datasets::Movies
85
+ end
86
+ end
87
+ end
88
+
89
+ describe ".validate" do
90
+
91
+ subject(:mut) { MSFL::Sinatra.validate params }
92
+
93
+ let(:params) { nil }
94
+
95
+ it_behaves_like "an invocation of MSFL::Sinatra.validate"
96
+ end
97
+ end
data/spec/spec_helper.rb CHANGED
@@ -3,4 +3,6 @@ SimpleCov.start 'msfl'
3
3
  require 'rspec/support/spec'
4
4
  require 'byebug'
5
5
  require_relative '../lib/msfl'
6
- require_relative 'msfl/shared_examples'
6
+ require_relative 'msfl/shared_examples'
7
+ require_relative '../lib/msfl/datasets/movies'
8
+ require_relative '../lib/msfl/datasets/cars'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: msfl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1.pre.rc1
4
+ version: 0.0.1.pre.rc2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Courtland Caldwell
@@ -112,9 +112,11 @@ files:
112
112
  - lib/msfl/configuration.rb
113
113
  - lib/msfl/datasets.rb
114
114
  - lib/msfl/datasets/base.rb
115
+ - lib/msfl/datasets/cars.rb
115
116
  - lib/msfl/datasets/movies.rb
116
117
  - lib/msfl/parsers.rb
117
118
  - lib/msfl/parsers/json.rb
119
+ - lib/msfl/sinatra.rb
118
120
  - lib/msfl/types.rb
119
121
  - lib/msfl/types/set.rb
120
122
  - lib/msfl/validators.rb
@@ -126,6 +128,8 @@ files:
126
128
  - spec/msfl/datasets/base_spec.rb
127
129
  - spec/msfl/parsers/json_spec.rb
128
130
  - spec/msfl/shared_examples.rb
131
+ - spec/msfl/sinatra/helpers_spec.rb
132
+ - spec/msfl/sinatra_spec.rb
129
133
  - spec/msfl/validators/semantic_spec.rb
130
134
  - spec/msfl_spec.rb
131
135
  - spec/spec_helper.rb
@@ -157,6 +161,8 @@ test_files:
157
161
  - spec/msfl/datasets/base_spec.rb
158
162
  - spec/msfl/parsers/json_spec.rb
159
163
  - spec/msfl/shared_examples.rb
164
+ - spec/msfl/sinatra/helpers_spec.rb
165
+ - spec/msfl/sinatra_spec.rb
160
166
  - spec/msfl/validators/semantic_spec.rb
161
167
  - spec/msfl_spec.rb
162
168
  - spec/spec_helper.rb