Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
523859b
Replace specs for expressions with shared library
bkeepers Mar 30, 2023
10fa1b4
Move expressions schemas into this repo
bkeepers Mar 30, 2023
a72ae35
Make Ruby 2.6 happy
bkeepers Mar 30, 2023
87c3de4
Use vitest to run tests
bkeepers Mar 31, 2023
0d065b5
Shuffle around somethings in schema.json and rename defs
bkeepers Mar 31, 2023
ee46fab
Add Min/Max functions
bkeepers Mar 31, 2023
6a2e622
Rename url-unfriendly defs
bkeepers Mar 31, 2023
08b03c1
Move expression examples out of test dir
bkeepers Mar 31, 2023
5004b6f
Initial docs for implementing functions
bkeepers Mar 31, 2023
4c35f3e
Run JS lint/tests
bkeepers Mar 31, 2023
c51eda3
Add not about running tests to expression docs
bkeepers Mar 31, 2023
50dc917
Fix README formatting
bkeepers Mar 31, 2023
6262795
Remove use of path
bkeepers Apr 1, 2023
4a10eaf
Simplfy schemas by making implementation cast function arguments to a…
bkeepers Apr 1, 2023
48308dd
Add json_schemer as a dependency
bkeepers Apr 1, 2023
81a1d65
Fix JS lint
bkeepers Apr 1, 2023
b8279c5
Validate schemas in strict mode
bkeepers Apr 2, 2023
270f290
$defs => definitions for draft 7
bkeepers Apr 3, 2023
8f69da4
Build sourcemaps
bkeepers Apr 10, 2023
a498b3a
Add explorer to inspect information about the schema
bkeepers Apr 4, 2023
a2c501a
Add simple js expression model
bkeepers Apr 4, 2023
a3b2076
Add validate method to Expression/Constant
bkeepers Apr 5, 2023
ad07179
Add simple schema class to browse and validate schemas
bkeepers Apr 8, 2023
d96ec78
Add proxying back to schema to resolve refs
bkeepers Apr 9, 2023
d134ae6
Add/Subtract/Multiply/Divide functions
bkeepers Apr 10, 2023
b4e7035
Fix bug where ajv eagerly resolves ref in array items
bkeepers Apr 10, 2023
7c5016b
use exported Schema class where possible
bkeepers Apr 10, 2023
26a08f3
Pair schema with expression and constant
bkeepers Apr 12, 2023
82cf6ac
Add operator keyword to schemas
bkeepers Apr 12, 2023
3f6d241
Allow null as a constant
bkeepers Jul 17, 2023
cfecaf5
Specify json_schemer version number
bkeepers Jul 17, 2023
e3b32c4
JS: Define expression.add(…) to build new expression
bkeepers Jul 19, 2023
0848411
Add parent to expressions, refactor
bkeepers Jul 25, 2023
639d2a7
Use external package for schemas
bkeepers Oct 12, 2023
8aa356c
Merge branch 'main' into expressions-schema
bkeepers Oct 12, 2023
6512d63
Add flipper-expressions-schema as separate gem for now
bkeepers Oct 12, 2023
21a0806
Merge remote-tracking branch 'origin/main' into expressions-schema
bkeepers Oct 12, 2023
9725f56
Ensure schemas are downloaded
bkeepers Oct 12, 2023
8e1bfb1
Ensure node is setup before bundling
bkeepers Oct 12, 2023
7fc02ff
Revert renaming of ci job
bkeepers Oct 12, 2023
15099b9
English properly
bkeepers Oct 12, 2023
6640afc
Don't auth to install npm/gems from github
bkeepers Oct 12, 2023
ed90c55
Try using the gem post_install hook to avoid issue with GitHub Actions
bkeepers Oct 13, 2023
6350f0e
Remove actions/cache, just rely on ruby/node actions for caching
bkeepers Oct 13, 2023
b36dd09
Run npm install before setting up ruby
bkeepers Oct 13, 2023
5470e59
Rename expressions repo
bkeepers Oct 13, 2023
afb896a
Merge remote-tracking branch 'origin/main' into expressions-schema
bkeepers Nov 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Allow null as a constant
  • Loading branch information
bkeepers committed Jul 17, 2023
commit 3f6d2410d69d37d7dd0cf378b51d73d13361abfd
2 changes: 1 addition & 1 deletion lib/flipper/expression.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def self.build(object)
args = args.is_a?(Hash) ? [args] : Array(args)

new(name, args.map { |o| build(o) })
when String, Numeric, FalseClass, TrueClass
when String, Numeric, FalseClass, TrueClass, nil
Expression::Constant.new(object)
when Symbol
Expression::Constant.new(object.to_s)
Expand Down
2 changes: 1 addition & 1 deletion lib/flipper/expressions/percentage.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module Flipper
module Expressions
class Percentage
def self.call(value)
value.to_f.clamp(0, 100)
value.clamp(0, 100)
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/flipper/gates/expression.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def open?(context)
end

def protects?(thing)
thing.is_a?(Flipper::Expression) || thing.is_a?(Hash)
thing.is_a?(Flipper::Expression) || thing.is_a?(Flipper::Expression::Constant) || thing.is_a?(Hash)
end

def wrap(thing)
Expand Down
8 changes: 8 additions & 0 deletions packages/expressions/examples/Equal.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@
"expression": { "Equal": ["a", "a"] },
"result": { "enum": [true] }
},
{
"expression": { "Equal": [null, null] },
"result": { "enum": [true] }
},
{
"expression": { "Equal": [null, false] },
"result": { "enum": [false] }
},
{
"expression": { "Equal": [1, 2] },
"result": { "enum": [false] }
Expand Down
5 changes: 4 additions & 1 deletion packages/expressions/examples/expressions.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@
{
"expression": 1.1,
"result": { "enum": [1.1] }
},
{
"expression": null,
"result": { "enum": [null] }
}
],
"invalid": [
null,
{},
[]
]
Expand Down
2 changes: 1 addition & 1 deletion packages/expressions/lib/constant.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Schema } from './schemas'
//
// Implements the same interface as Expression
export class Constant {
constructor (value, { id = uuidv4(), schema = Schema.resolve('#/definitions/constant') } = {}) {
constructor (value, { id = uuidv4(), schema = Schema.resolve('#') } = {}) {
this.value = value
this.id = id
this.schema = schema
Expand Down
16 changes: 6 additions & 10 deletions packages/expressions/lib/expression.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,9 @@ import { Constant } from './constant'
import { Schema } from './schemas'

function toArray (arg) {
if (Array.isArray(arg)) {
return arg
} else if (arg === null) {
return []
} else {
return [arg]
}
if (Array.isArray(arg)) return arg
if (arg === null) return []
return [arg]
}

// Simple model to transform this: `{ All: [{ Boolean: [true] }]`
Expand All @@ -20,14 +16,14 @@ export class Expression {
return expression
}

if (typeof expression === 'object') {
if (['number', 'string', 'boolean'].includes(typeof expression) || expression === null) {
return new Constant(expression, { schema })
} else if (typeof expression === 'object') {
if (Object.keys(expression).length !== 1) {
throw new TypeError(`Invalid expression: ${JSON.stringify(expression)}`)
}
const name = Object.keys(expression)[0]
return new Expression({ name, args: expression[name] })
} else if (['number', 'string', 'boolean'].includes(typeof expression)) {
return new Constant(expression, { schema })
} else {
throw new TypeError(`Invalid expression: ${JSON.stringify(expression)}`)
}
Expand Down
3 changes: 3 additions & 0 deletions packages/expressions/schemas/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
"title": "Boolean",
"type": "boolean",
"enum": [true, false]
},
{
"type": "null"
}
]
},
Expand Down
5 changes: 2 additions & 3 deletions packages/expressions/test/constant.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { Constant, Schema } from '../lib'

describe('Constant', () => {
describe('schema', () => {
test('defaults to Constant schema', () => {
expect(new Constant('string').schema.title).toEqual('Constant')
test('defaults to expression schema', () => {
expect(new Constant('string').schema.title).toEqual('Expression')
})

test('uses provided schema', () => {
Expand All @@ -26,7 +26,6 @@ describe('Constant', () => {

test('returns false for invalid value', () => {
expect(new Constant(['array']).validate().valid).toBe(false)
expect(new Constant({Now: []}).validate().valid).toBe(false)
})

test('uses provided schema', () => {
Expand Down
25 changes: 24 additions & 1 deletion packages/expressions/test/expression.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,24 @@ describe('Expression', () => {
expect(expression.value).toEqual({ All: [true] })
})

test('builds an expression from a boolean constant', () => {
const expression = Expression.build(true)
expect(expression).toBeInstanceOf(Constant)
expect(expression.value).toEqual(true)
})

test('builds an expression from a string constant', () => {
const expression = Expression.build('hello')
expect(expression).toBeInstanceOf(Constant)
expect(expression.value).toEqual('hello')
})

test('builds an expression from a null constant', () => {
const expression = Expression.build(null)
expect(expression).toBeInstanceOf(Constant)
expect(expression.value).toEqual(null)
})

test('throws error on invalid expression', () => {
expect(() => Expression.build([])).toThrowError(TypeError)
expect(() => Expression.build(new Date())).toThrowError(TypeError)
Expand All @@ -25,8 +43,13 @@ describe('Expression', () => {
expect(expression.args[1].schema).toEqual(schema.items[1])
})

test('sets schema for constant', () => {
const expression = Expression.build(false)
expect(expression.schema.$id).toEqual(Schema.resolve('#').$id)
})

test('each subexpression uses its own schema', () => {
const expression = Expression.build({ GreaterThan: [ { Now: [] }, { Property: ['released_at'] } ] })
const expression = Expression.build({ GreaterThan: [{ Now: [] }, { Property: ['released_at'] }] })
expect(expression.schema).toEqual(Schema.resolve('GreaterThan.schema.json'))
expect(expression.args[0].schema).toEqual(Schema.resolve('Now.schema.json'))
expect(expression.args[1].schema).toEqual(Schema.resolve('Property.schema.json'))
Expand Down
4 changes: 2 additions & 2 deletions packages/expressions/test/schemas.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,12 @@ describe('schema.json', () => {
describe('resolveAnyOf', () => {
test('returns nested anyOf', () => {
const ref = Schema.resolve('#')
expect(ref.resolveAnyOf()).toHaveLength(4)
expect(ref.resolveAnyOf()).toHaveLength(5)
})

test('returns array of schemas', () => {
const ref = Schema.resolve('#/definitions/constant')
expect(ref.resolveAnyOf()).toHaveLength(3)
expect(ref.resolveAnyOf()).toHaveLength(4)
expect(ref.resolveAnyOf()).toEqual(ref.anyOf)
})
})
Expand Down
5 changes: 5 additions & 0 deletions spec/flipper/gates/expression_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@ def context(expression, properties: {})
expect(subject.protects?(expression)).to be(true)
end

it 'returns true for Flipper::Constant' do
expression = Flipper.boolean(true)
expect(subject.protects?(expression)).to be(true)
end

it 'returns true for Hash' do
expression = Flipper.number(20).eq(20)
expect(subject.protects?(expression.value)).to be(true)
Expand Down