Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
4 changes: 4 additions & 0 deletions Hammerspoon Tests/HSmath.m
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ - (void)testRandomFloat {
RUN_LUA_TEST()
}

- (void)testRandomFloatFromRange {
RUN_LUA_TEST()
}

- (void)testRandomFromRange {
RUN_LUA_TEST()
}
Expand Down
688 changes: 686 additions & 2 deletions Hammerspoon.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

66 changes: 66 additions & 0 deletions Hammerspoon.xcodeproj/xcshareddata/xcschemes/Hammertime.xcscheme
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1510"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "4F61CD862B32F58000407260"
BuildableName = "Hammertime.framework"
BlueprintName = "Hammertime"
ReferencedContainer = "container:Hammerspoon.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "4F61CD862B32F58000407260"
BuildableName = "Hammertime.framework"
BlueprintName = "Hammertime"
ReferencedContainer = "container:Hammerspoon.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
13 changes: 13 additions & 0 deletions Hammertime/Hammertime.docc/Hammertime.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# ``Hammertime``

<!--@START_MENU_TOKEN@-->Summary<!--@END_MENU_TOKEN@-->

## Overview

<!--@START_MENU_TOKEN@-->Text<!--@END_MENU_TOKEN@-->

## Topics

### <!--@START_MENU_TOKEN@-->Group<!--@END_MENU_TOKEN@-->

- <!--@START_MENU_TOKEN@-->``Symbol``<!--@END_MENU_TOKEN@-->
19 changes: 19 additions & 0 deletions Hammertime/Hammertime.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// Hammertime.h
// Hammertime
//
// Created by Chris Jones on 20/12/2023.
// Copyright © 2023 Hammerspoon. All rights reserved.
//

#import <Foundation/Foundation.h>

//! Project version number for Hammertime.
FOUNDATION_EXPORT double HammertimeVersionNumber;

//! Project version string for Hammertime.
FOUNDATION_EXPORT const unsigned char HammertimeVersionString[];

// In this header, you should import all the public headers of your framework using statements like #import <Hammertime/PublicHeader.h>


69 changes: 69 additions & 0 deletions Hammertime/Math.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//
// Math.swift
// Hammertime
//
// Created by Chris Jones on 20/12/2023.
// Copyright © 2023 Hammerspoon. All rights reserved.
//

import Foundation

@objc
public class Math : NSObject {
@objc
public func validateDoubleRange(start: Double, end: Double) -> Bool {
return start <= end
}

@objc
public func validateIntRange(start: Int, end: Int) -> Bool {
return start <= end
}

/// Returns a random Double between 0 and 1 (inclusive)
/// - Returns: Double
@objc
public func randomDouble() -> Double {
return self.randomDoubleInRange(start: 0, end: 1)
}

/// Returns a random Doubld within the supplied range (inclusive)
/// - Parameters:
/// - start: Lower bound of the range
/// - end: Upper bound of the range
/// - Returns: Double
@objc
public func randomDoubleInRange(start: Double, end: Double) -> Double {
if (!self.validateDoubleRange(start: start, end: end)) {
NSException.raise(.rangeException, format: "start must be <= end", arguments: getVaList([""]))
}
return Double.random(in: start...end)
}

/// Returns a random Float between 0 and 1 (inclusive)
/// - Returns: Float
@objc
public func randomFloat() -> Float {
return self.randomFloatInRange(start: 0, end: 1)
}

/// Returns a random Float within the supplied range (inclusive)
/// - Parameters:
/// - start: Lower bound of the range
/// - end: Upper bound of the range
/// - Returns: Float
@objc
public func randomFloatInRange(start: Float, end: Float) -> Float {
return Float.random(in: start...end)
}

/// Returns a random Int within the supplied range (inclusive)
/// - Parameters:
/// - start: Lower bound of the range
/// - end: Upper bound of the range
/// - Returns: Int
@objc
public func randomIntInRange(start: Int, end: Int) -> Int {
return Int.random(in: start...end)
}
}
37 changes: 37 additions & 0 deletions HammertimeTests/HammertimeTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//
// HammertimeTests.swift
// HammertimeTests
//
// Created by Chris Jones on 20/12/2023.
// Copyright © 2023 Hammerspoon. All rights reserved.
//

import XCTest
@testable import Hammertime

final class HammertimeTests: XCTestCase {

override func setUpWithError() throws {
// Put setup code here. This method is called before the invocation of each test method in the class.
}

override func tearDownWithError() throws {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}

func testExample() throws {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
// Any test you write for XCTest can be annotated as throws and async.
// Mark your test throws to produce an unexpected failure when your test encounters an uncaught error.
// Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards.
}

func testPerformanceExample() throws {
// This is an example of a performance test case.
self.measure {
// Put the code you want to measure the time of here.
}
}

}
53 changes: 43 additions & 10 deletions extensions/math/libmath.m
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
@import Cocoa ;
@import LuaSkin ;
@import Hammertime ;

#import <stdlib.h>

Expand All @@ -16,10 +17,42 @@ static int math_randomFloat(lua_State* L) {
LuaSkin *skin = [LuaSkin sharedWithState:L];
[skin checkArgs:LS_TBREAK];

uint32_t rand = arc4random();
double val = ((double)rand / UINT32_MAX);
Math *math = [[Math alloc] init];
lua_pushnumber(L, [math randomDouble]);

lua_pushnumber(L, val);
return 1;
}

/// hs.math.randomFloatFromRange(start, end) -> number
/// Function
/// Returns a random floating point number in the supplied range
///
/// Parameters:
/// * start - Lower bound of the range
/// * end - Upper bound of the range
///
/// Returns:
/// * A random number
static int math_randomFloatFromRange(lua_State *L) {
LuaSkin *skin = [LuaSkin sharedWithState:L];
[skin checkArgs:LS_TNUMBER, LS_TNUMBER, LS_TBREAK];

Math *math = [[Math alloc] init];
// double start = lua_tonumber(L, 1);
// double end = lua_tonumber(L, 2);

// if (![math validateDoubleRangeWithStart:start end:end]) {
// [skin logError:@"hs.math.randomFloatFromRange: start must be <= end"];
// lua_pushnil(L);
// return 1;
// }

@try {
lua_pushnumber(L, [math randomDoubleInRangeWithStart:lua_tonumber(L, 1) end:lua_tonumber(L, 2)]);
} @catch (NSException *e){
[skin logError:e.reason];
lua_pushnil(L);
}
return 1;
}

Expand All @@ -28,33 +61,33 @@ static int math_randomFloat(lua_State* L) {
/// Returns a random integer between the start and end parameters
///
/// Parameters:
/// * start - A number to start the range, must be greater than or equal to zero
/// * end - A number to end the range, must be greater than zero and greater than `start`
/// * start - Lower bound of the range
/// * end - Upper bound of the range
///
/// Returns:
/// * A randomly chosen integer between `start` and `end`
static int math_randomFromRange(lua_State* L) {
LuaSkin *skin = [LuaSkin sharedWithState:L] ;
[skin checkArgs:LS_TNUMBER, LS_TNUMBER, LS_TBREAK] ;

Math *math = [[Math alloc] init];
int start = (int)lua_tointeger(L, 1);
int end = (int)lua_tointeger(L, 2);

if (start < 0 || end <= 0 || end <= start) {
[skin logError:[NSString stringWithFormat:@"Please check the docs for hs.math.randomForRange() - your range is not acceptable (%d -> %d)", start, end]];
if (![math validateIntRangeWithStart:start end:end]) {
[skin logError:@"hs.math.randomFromRange: start must be <= end"];
lua_pushnil(L);
return 1;
}

int result = arc4random_uniform(end - start + 1) + start;

lua_pushinteger(L, result);
lua_pushinteger(L, [math randomIntInRangeWithStart:lua_tointeger(L, 1) end:lua_tointeger(L, 2)]);
return 1;
}

// Functions for returned object when module loads
static const luaL_Reg mathLib[] = {
{"randomFloat", math_randomFloat},
{"randomFloatFromRange", math_randomFloatFromRange},
{"randomFromRange", math_randomFromRange},

{NULL, NULL}
Expand Down
27 changes: 25 additions & 2 deletions extensions/math/test_math.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,39 @@ function testRandomFloat()
return success()
end

function testRandomFloatFromRange()
local i = 10
while i > 0 do
local rand = hs.math.randomFloatFromRange(0, 100)
assertTrue(rand >= 0)
assertTrue(rand <= 100)
i = i - 1
end

local rand1 = hs.math.randomFloatFromRange(-1, 100)
assertTrue(rand1 >= -1)
assertTrue(rand1 <= 100)

local rand2 = hs.math.randomFloatFromRange(1, 1)
assertTrue(rand2 == 1)

local rand3 = hs.math.randomFloatFromRange(100, 1)
assertIsNil(rand3)

return success()
end

function testRandomFromRange()
local rand1 = hs.math.randomFromRange(0, 100)
assertTrue(rand1 >= 0)
assertTrue(rand1 <= 100)

local rand2 = hs.math.randomFromRange(-1, 100)
assertIsNil(rand2)
assertTrue(rand2 >= -1)
assertTrue(rand2 <= 100)

local rand3 = hs.math.randomFromRange(1, 1)
assertIsNil(rand3)
assertTrue(rand3 == 1)

local rand4 = hs.math.randomFromRange(1, -1)
assertIsNil(rand4)
Expand Down