Skip to content

Commit

Permalink
Merge branch 'development'
Browse files Browse the repository at this point in the history
  • Loading branch information
jclausen committed Jan 11, 2025
2 parents d8fc49f + 30a8c0a commit 57d4879
Show file tree
Hide file tree
Showing 9 changed files with 190 additions and 56 deletions.
4 changes: 2 additions & 2 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#Tue Dec 10 21:54:51 UTC 2024
#Tue Dec 17 18:03:19 UTC 2024
boxlangVersion=1.0.0-snapshot
jdkVersion=21
version=1.15.0
version=1.16.0
group=ortus.boxlang
7 changes: 7 additions & 0 deletions src/main/bx/ModuleConfig.bx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* Every Module will have it's own ClassLoader that will be used to load the module libs and dependencies.
*/
import ortus.boxlang.runtime.context.BaseBoxContext;
import ortus.boxlang.runtime.dynamic.casters.NumberCaster;

class {

Expand Down Expand Up @@ -96,6 +97,9 @@ import ortus.boxlang.runtime.context.BaseBoxContext;
clientTimeout = createTimeSpan( 0, 1, 0, 0 ),
// Mimic the CF behavior of nulls being undefined. Set this to false to have full null support
nullIsUndefined = true,
// Mimic the CF and Lucee 5 behavior of boolean true/false being 1/0 and usable in math operations.
// Also affects the isNumeric() BIF. To match Lucee 6, set this to false.
booleansAreNumbers = true,
// JSON control character auto-escaping flag
// IF you turn to true, be aware that the entire JSON serialization will be escaped and be slower.
jsonEscapeControlCharacters = true,
Expand Down Expand Up @@ -150,6 +154,9 @@ import ortus.boxlang.runtime.context.BaseBoxContext;
// Set the nullIsUndefined flag. This is stored statically on the base context for best performance
BaseBoxContext.nullIsUndefined = settings.nullIsUndefined;

// Set this statically for best performance
NumberCaster.booleansAreNumbers = settings.booleansAreNumbers;

// Verify Engine
if( isNull( settings.engine ) || settings.engine.isEmpty() ){
throw( "You must specify an [engine] in the settings. Valid engines are [adobe,lucee]" );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@
*/
package ortus.boxlang.modules.compat.bifs.cache;

import java.util.Set;

import ortus.boxlang.modules.compat.util.KeyDictionary;
import ortus.boxlang.runtime.bifs.BIF;
import ortus.boxlang.runtime.bifs.BoxBIF;
import ortus.boxlang.runtime.cache.providers.ICacheProvider;
Expand All @@ -26,6 +25,7 @@
import ortus.boxlang.runtime.scopes.Key;
import ortus.boxlang.runtime.types.Argument;
import ortus.boxlang.runtime.types.Array;
import ortus.boxlang.runtime.types.exceptions.BoxRuntimeException;
import ortus.boxlang.runtime.validation.Validator;

@BoxBIF
Expand All @@ -40,7 +40,8 @@ public CacheGet() {
super();
declaredArguments = new Argument[] {
new Argument( true, Argument.ANY, Key.id ),
new Argument( false, Argument.STRING, Key.cacheName, Key._DEFAULT, Set.of( cacheExistsValidator ) )
new Argument( false, Argument.ANY, Key.cacheName, Key._DEFAULT ),
new Argument( false, Argument.ANY, KeyDictionary.throwWhenNotExist, false )
};
}

Expand All @@ -58,6 +59,20 @@ public CacheGet() {
* @return The value of the object in the cache or null if not found, or the default value if provided
*/
public Object _invoke( IBoxContext context, ArgumentsScope arguments ) {
if ( arguments.get( Key.cacheName ) instanceof Boolean ) {
// Handle lucees method signature with a boolean as the second arg
Key cacheName = Key._DEFAULT;
if ( arguments.get( KeyDictionary.throwWhenNotExist ) != null ) {
cacheName = Key.of( arguments.getAsString( KeyDictionary.throwWhenNotExist ) );
}
arguments.put( KeyDictionary.throwWhenNotExist, arguments.getAsBoolean( Key.cacheName ) );
arguments.put( Key.cacheName, cacheName );
}

if ( arguments.get( Key.cacheName ) instanceof String ) {
arguments.put( Key.cacheName, Key.of( arguments.getAsString( Key.cacheName ) ) );
}

// Get the requested cache
ICacheProvider cache = cacheService.getCache( arguments.getAsKey( Key.cacheName ) );

Expand All @@ -68,9 +83,16 @@ public Object _invoke( IBoxContext context, ArgumentsScope arguments ) {
}

// Get the value
Attempt<Object> results = cache.get( arguments.getAsString( Key.id ) );
Attempt<Object> results = cache.get( arguments.getAsString( Key.id ) );
// If we have a value return it, else do we have a defaultValue, else return null
return results.orElse( null );
Object item = results.orElse( null );
if ( item == null && arguments.getAsBoolean( KeyDictionary.throwWhenNotExist ) ) {
throw new BoxRuntimeException(
"Item not found in cache [" + arguments.getAsKey( Key.cacheName ).getName() + "]: " + arguments.getAsString( Key.id )
);
} else {
return item;
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,7 @@ public Object _invoke( IBoxContext context, ArgumentsScope arguments ) {
Object value = arguments.get( Key.value );

// DynamicObject instances need to be unwrapped to get the metadata
if ( value instanceof DynamicObject dynamicObject ) {
if ( dynamicObject.hasInstance() ) {
value = dynamicObject.unWrap();
} else {
value = dynamicObject.invokeConstructor( context ).unWrap();
}
}
value = DynamicObject.unWrap( value );

// Functions have a legacy metadata view that matches CF engines
if ( value instanceof Function fun ) {
Expand All @@ -87,6 +81,10 @@ public Object _invoke( IBoxContext context, ArgumentsScope arguments ) {
}

// All other types return the class of the value to match CF engines
if ( value instanceof Class ) {
return value;
}

return value.getClass();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public class KeyDictionary {
public static final Key client = Key.of( "client" );
public static final Key clientStorage = Key.of( "clientStorage" );
public static final Key clientTimeout = Key.of( "clientTimeout" );
public static final Key throwWhenNotExist = Key.of( "throwWhenNotExist" );
public static final Key ON_CLIENT_CREATED = Key.of( "onClientCreated" );
public static final Key ON_CLIENT_DESTROYED = Key.of( "onClientDestroyed" );

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package ortus.boxlang.modules.compat;

import static com.google.common.truth.Truth.assertThat;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import ortus.boxlang.runtime.dynamic.casters.NumberCaster;
import ortus.boxlang.runtime.operators.Negate;

/**
* This loads the module and runs an integration test on the module.
*/
public class BooleansAreNumbersTest extends BaseIntegrationTest {

@DisplayName( "It can cast a boolean to a Number" )
@Test
void testItCanCastABoolean() {
Number result = NumberCaster.cast( true );
assertThat( result ).isInstanceOf( Integer.class );
assertThat( result.doubleValue() ).isEqualTo( 1 );

result = NumberCaster.cast( false );
assertThat( result ).isInstanceOf( Integer.class );
assertThat( result.doubleValue() ).isEqualTo( 0 );

result = NumberCaster.cast( "true" );
assertThat( result ).isInstanceOf( Integer.class );
assertThat( result.doubleValue() ).isEqualTo( 1 );

result = NumberCaster.cast( "false" );
assertThat( result ).isInstanceOf( Integer.class );
assertThat( result.doubleValue() ).isEqualTo( 0 );

result = NumberCaster.cast( "yes" );
assertThat( result ).isInstanceOf( Integer.class );
assertThat( result.doubleValue() ).isEqualTo( 1 );

result = NumberCaster.cast( "no" );
assertThat( result ).isInstanceOf( Integer.class );
assertThat( result.doubleValue() ).isEqualTo( 0 );
}

@DisplayName( "It can mathematically negate a boolean" )
@Test
void testItCanNegateBoolean() {
assertThat( Negate.invoke( true ) ).isEqualTo( -1 );
assertThat( Negate.invoke( false ) ).isEqualTo( 0 );
assertThat( Negate.invoke( "true" ) ).isEqualTo( -1 );
assertThat( Negate.invoke( "false" ) ).isEqualTo( 0 );
assertThat( Negate.invoke( "yes" ) ).isEqualTo( -1 );
assertThat( Negate.invoke( "no" ) ).isEqualTo( 0 );
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@
package ortus.boxlang.modules.compat.bifs.cache;

import static com.google.common.truth.Truth.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import ortus.boxlang.runtime.types.exceptions.BoxRuntimeException;

public class CacheGetTest extends BaseCacheTest {

@Test
Expand Down Expand Up @@ -60,4 +63,29 @@ public void canGetNullFromInvalidCacheKey() {
assertThat( variables.get( "result" ) ).isNull();
}

@Test
@DisplayName( "Can retrieve a cache object using Lucees method signature" )
public void canGetWithLuceeSignature() {
runtime.executeSource(
"""
result = cacheGet( "tdd", false, "default" );
""",
context );

assertThat( variables.get( "result" ) ).isEqualTo( "rocks" );
}

@Test
@DisplayName( "Can retrieve a cache object using Lucees method signature with throwWhenNotExist" )
public void canGetWithLuceeSignatureAndThrowWhenNotExist() {
assertThrows(
BoxRuntimeException.class,
() -> runtime.executeSource(
"""
result = cacheGet( "invalid", true, "default" );
""",
context )
);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* [BoxLang]
*
* Copyright [2023] [Ortus Solutions, Corp]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS"
* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
package ortus.boxlang.modules.compat.bifs.format;

import static com.google.common.truth.Truth.assertThat;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import ortus.boxlang.modules.compat.BaseIntegrationTest;

public class NumberFormatTest extends BaseIntegrationTest {

// https://ortussolutions.atlassian.net/browse/BL-890
@DisplayName( "It formats a boolean as a number" )
@Test
void testFormatBooleanAsNumber() {
runtime.executeSource(
"""
result = numberFormat(0 IS 0);
""",
context );
assertThat( variables.get( result ) ).isEqualTo( "1" );

}

}
Loading

0 comments on commit 57d4879

Please sign in to comment.