DSE6 + .NET v?

Project Repo: Interoperability Black Box

First steps. Let’s get .NET installed and setup. I’m running Ubuntu 18.04 for this setup and start of project. To install .NET on Ubuntu one needs to go through a multi-command process of keys and some other stuff, fortunately Microsoft’s teams have made this almost easy by providing the commands for the various Linux distributions here. The commands I ran are as follows to get all this initial setup done.

[sourcecode language=”bash”]
wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg –dearmor > microsoft.asc.gpg
sudo mv microsoft.asc.gpg /etc/apt/trusted.gpg.d/
wget -q https://packages.microsoft.com/config/ubuntu/18.04/prod.list
sudo mv prod.list /etc/apt/sources.list.d/microsoft-prod.list
sudo chown root:root /etc/apt/trusted.gpg.d/microsoft.asc.gpg
sudo chown root:root /etc/apt/sources.list.d/microsoft-prod.list
[/sourcecode]

After all this I could then install the .NET SDK. It’s been so long since I actually installed .NET on anything that I wasn’t sure if I just needed the runtime, the SDK, or what I’d actually need. I just assumed it would be safe to install the SDK and then install the runtime too.

[sourcecode language=”bash”]
sudo apt-get install apt-transport-https
sudo apt-get update
sudo apt-get install dotnet-sdk-2.1
[/sourcecode]

Then the runtime.

[sourcecode language=”bash”]
sudo apt-get install aspnetcore-runtime-2.1
[/sourcecode]

logoAlright. Now with this installed, I wanted to also see if Jetbrains Rider would detect – or at least what would I have to do – to have the IDE detect that .NET is now installed. So I opened up the IDE to see what the results would be. Over the left hand side of the new solution dialog, if anything isn’t installed Rider usually will display a message that X whatever needs installed. But it looked like everything is showing up as installed, “yay for things working (at this point)!

rider-01

Next up is to get a solution started with the pertinent projects for what I want to build.

dse2

Kazam_screenshot_00001

For the next stage I created three projects.

  1. InteroperationalBlackBox – A basic class library that will be used by a console application or whatever other application or service that may need access to the specific business logic or what not.
  2. InteroperationalBlackBox.Tests – An xunit testing project for testing anything that might need some good ole’ testing.
  3. InteroperationalBlackBox.Cli – A console application (CLI) that I’ll use to interact with the class library and add capabilities going forward.

Alright, now that all the basic projects are setup in the solution, I’ll go out and see about the .NET DataStax Enterprise driver. Inside Jetbrains Rider I can right click on a particular project that I want to add or manage dependencies for. I did that and then put “dse” in the search box. The dialog pops up from the bottom of the IDE and you can add it by clicking on the bottom right plus sign in the description box to the right. Once you click the plus sign, once installed, it becomes a little red x.

dse-adding-package

Alright. Now it’s almost time to get some code working. We need ourselves a database first however. I’m going to setup a cluster in Google Cloud Platform (GCP), but feel free to use whatever cluster you’ve got. These instructions will basically be reusable across wherever you’ve got your cluster setup. I wrote up a walk through and instructions for the GCP Marketplace a few weeks ago. I used the same offering to get this example cluster up and running to use. So, now back to getting the first snippets of code working.

Let’s write a test first.

[sourcecode language=”csharp”]
[Fact]
public void ConfirmDatabase_Connects_False()
{
var box = new BlackBox();
Assert.Equal(false, box.ConfirmConnection());
}
[/sourcecode]

In this test, I named the class called BlackBox and am planning to have a parameterless constructor. But as things go tests are very fluid, or ought to be, and I may change it in the next iteration. I’m thinking, at least to get started, that I’ll have a method to test and confirm a connection for the CLI. I’ve named it ConfirmConnection for that purpose. Initially I’m going to test for false, but that’s primarily just to get started. Now, time to implement.

[sourcecode language=”csharp”]
namespace InteroperabilityBlackBox
using System;
using Dse;
using Dse.Auth;

namespace InteroperabilityBlackBox
{
public class BlackBox
{
public BlackBox()
{}

public bool ConfirmConnection()
{
return false;
}
}
}
[/sourcecode]

That gives a passing test and I move forward. For more of the run through of moving from this first step to the finished code session check out this

By the end of the coding session I had a few tests.

[sourcecode language=”csharp”]
using Xunit;

namespace InteroperabilityBlackBox.Tests
{
public class MakingSureItWorksIntegrationTests
{
[Fact]
public void ConfirmDatabase_Connects_False()
{
var box = new BlackBox();
Assert.Equal(false, box.ConfirmConnection());
}

[Fact]
public void ConfirmDatabase_PassedValuesConnects_True()
{
var box = new BlackBox(“cassandra”, “”, “”);
Assert.Equal(false, box.ConfirmConnection());
}

[Fact]
public void ConfirmDatabase_PassedValuesConnects_False()
{
var box = new BlackBox(“cassandra”, “notThePassword”, “”);
Assert.Equal(false, box.ConfirmConnection());
}
}
}
[/sourcecode]

The respective code for connecting to the database cluster, per the walk through I wrote about here, at session end looked like this.

[sourcecode language=”csharp”]
using System;
using Dse;
using Dse.Auth;

namespace InteroperabilityBlackBox
{
public class BlackBox : IBoxConnection
{
public BlackBox(string username, string password, string contactPoint)
{
UserName = username;
Password = password;
ContactPoint = contactPoint;
}

public BlackBox()
{
UserName = “ConfigValueFromSecretsVault”;
Password = “ConfigValueFromSecretsVault”;
ContactPoint = “ConfigValue”;
}

public string ContactPoint { get; set; }
public string UserName { get; set; }
public string Password { get; set; }

public bool ConfirmConnection()
{
IDseCluster cluster = DseCluster.Builder()
.AddContactPoint(ContactPoint)
.WithAuthProvider(new DsePlainTextAuthProvider(UserName, Password))
.Build();

try
{
cluster.Connect();
return true;
}
catch (Exception e)
{
Console.WriteLine(e);
return false;
}

}
}
}
[/sourcecode]

With my interface providing the contract to meet.

[sourcecode language=”csharp”]
namespace InteroperabilityBlackBox
{
public interface IBoxConnection
{
string ContactPoint { get; set; }
string UserName { get; set; }
string Password { get; set; }
bool ConfirmConnection();
}
}
[/sourcecode]

Conclusions & Next Steps

After I wrapped up the session two things stood out that needed fixed for the next session. I’ll be sure to add these as objectives for the next coding session at 3pm PST on Thursday.

  1. The tests really needed to more resiliently confirm the integrations that I was working to prove out. My plan at this point is to add some Docker images that would provide the development integration tests a point to work against. This would alleviate the need for something outside of the actual project in the repository to exist. Removing that fragility.
  2. The application, in its “Black Box”, should do something. For the next session we’ll write up some feature requests we’d want, or maybe someone has some suggestions of functionality they’d like to see implemented in a CLI using .NET Core working against a DataStax Enterprise Cassandra Database Cluster? Feel free to leave a comment or three about a feature, I’ll work on adding it during the next session.

Chapter 2 in My Twitch Streaming

A while back I started down the path of getting a Twitch Channel started. At this point I’ve gotten a channel setup which I’ve dubbed Thrashing Code albeit it still just has “adronhall” all over it. I’ll get those details further refined as I work on it more.

Today I recorded a new Twitch stream about doing a twitch stream and created an edited video of all the pieces and cameras and angles. I could prospectively help people get started, it’s just my experiences so far and efforts to get everything connected right. The actual video stream recording is available, and I’ll leave it on the channel. However the video I edited will be available and I’ll post a link here.

Tomorrow will be my first official Twitch stream at 3pm PST. If you’re interested in watching check out my Twitch profile here follow and it’ll ping you when I go live. This first streaming session, or episode, or whatever you want to call it, will include a couple topics. I’ll be approaching these topics from that of someone just starting, so if you join help hold me to that! Don’t let me skip ahead or if you notice I left out something key please join and chat at me during the process. I want to make sure I’m covering all the bases as I step through toward achieving the key objectives. Which speaking of…

Tomorrow’s Mission Objectives

  1. Create a DataStax Enterprise Cassandra Cluster in Google Cloud Platform.
  2. Create a .NET project using the latest cross-platform magical bits that will have a library for abstracting the data source(s), a console interface for using the application, and of course a test project.
  3. Configure & connect to the distributed database cluster.

Mission Stretch Objectives

  1. Start a github repo to share the project with others.
  2. Setup some .github templates for feature request issues or related issues.
  3. Write up some Github Issue Feature requests and maybe even sdd some extra features to the CLI for…??? no idea ??? determine 2-3 during the Twitch stream.

If you’d like to follow along, here’s what I have installed. You’re welcome to a range of tooling to follow along with that is the same as what I’ve got here or a variance of other things. Feel free to bring up tooling if you’re curious about it via chat and I’ll answer questions where and when I can.

  • Ubuntu v18.04
  • .NET core v2.1
  • DataStax Enterprise v6

______10 |> F# – Moar Thinking Functionally (Notes)

More notes on the “Thinking Functionally” series. Previous notes are @ “_______1 |> F# – Getting Started, Thinking Functionally“.

#6 Partial Application

Breaking down functions into single parameter functions is the mathematically correct way of doing it, but that is not the only reason it is done — it also leads to a very powerful technique called partial function application.

For example:

[sourcecode language=”fsharp”]
let add42 = (+) 42 // partial application
add42 1
add42 3

[1;2;3] |> List.map add42

let twoIsLessThan = (<) 2 // partial application twoIsLessThan 1 twoIsLessThan 3 // filter each element with the twoIsLessThan function [1;2;3] |> List.filter twoIsLessThan

let printer = printfn "printing param=%i"

[1;2;3] |> List.iter printer
[/sourcecode]

Each case a partially applied function above it can then be reused in multiple contexts. It can also fix function parameters.

[sourcecode language=”fsharp”]
let add1 = (+) 1
let add1ToEach = List.map add1 // fix the "add1" function

add1ToEach [1;2;3;4]

let filterEvens =
List.filter (fun i -> i%2 = 0) // fix the filter function

filterEvens [1;2;3;4]
[/sourcecode]

Then the following shows plug in behavior that is transparent.

[sourcecode language=”fsharp”]
let adderWithPluggableLogger logger x y =
logger "x" x
logger "y" y
let result = x + y
logger "x+y" result
result

let consoleLogger argName argValue =
printfn "%s=%A" argName argValue

let addWithConsoleLogger = adderWithPluggableLogger consoleLogger
addWithConsoleLogger 1 2
addWithConsoleLogger 42 99

let popupLogger argName argValue =
let message = sprintf "%s=%A" argName argValue
System.Windows.Forms.MessageBox.Show(
text=message,caption="Logger")
|> ignore

let addWithPopupLogger = adderWithPluggableLogger popupLogger
addWithPopupLogger 1 2
addWithPopupLogger 42 99
[/sourcecode]

Designing Functions for Partial Application

Sample calls to the list library:

[sourcecode language=”fsharp”]
List.map (fun i -> i+1) [0;1;2;3]
List.filter (fun i -> i>1) [0;1;2;3]
List.sortBy (fun i -> -i ) [0;1;2;3]
[/sourcecode]

Here are the same examples using partial application:

[sourcecode language=”fsharp”]
let eachAdd1 = List.map (fun i -> i+1)
eachAdd1 [0;1;2;3]

let excludeOneOrLess = List.filter (fun i -> i>1)
excludeOneOrLess [0;1;2;3]

let sortDesc = List.sortBy (fun i -> -i)
sortDesc [0;1;2;3]
[/sourcecode]

Commonly accepted guidelines to multi-parameter function design.

  1. Put earlier: parameters ore likely to be static. The parameters that are most likely to be “fixed” with partial application should be first.
  2. Put last: the data structure or collection (or most varying argument). Makes it easier to pipe a structure or collection from function to function. Like:

    [sourcecode language=”fsharp”]
    let result =
    [1..10]
    |> List.map (fun i -> i+1)
    |> List.filter (fun i -> i>5)
    [/sourcecode]

  3. For well-known operations such as “subtract”, put in the expected order.

Wrapping BCL Function for Partial Application

Since the data parameter is generally last versus most BCL calls that have the data parameter first, it’s good to wrap the BCL.

[sourcecode language=”fsharp”]
let replace oldStr newStr (s:string) =
s.Replace(oldValue=oldStr, newValue=newStr)

let startsWith lookFor (s:string) =
s.StartsWith(lookFor)
[/sourcecode]

Then pipes can be used with the BCL call in the expected way.

[sourcecode language=”fsharp”]
let result =
"hello"
|> replace "h" "j"
|> startsWith "j"

["the"; "quick"; "brown"; "fox"]
|> List.filter (startsWith "f")
[/sourcecode]

…or we can use function composition.

[sourcecode language=”fsharp”]
let compositeOp = replace "h" "j" >> startsWith "j"
let result = compositeOp "hello"
[/sourcecode]

Understanding the Pipe Function

The pipe function is defined as:

[sourcecode language=”fsharp”]
let (|>) x f = f x
[/sourcecode]

It allows us to put the function argument in front of the function instead of after.

[sourcecode language=”fsharp”]
let doSomething x y z = x+y+z
doSomething 1 2 3
[/sourcecode]

If the function has multiple parameters, then it appears that the input is the final parameter. Actually what is happening is that the function is partially applied, returning a function that has a single parameter: the input.

[sourcecode language=”fsharp”]
let doSomething x y =
let intermediateFn z = x+y+z
intermediateFn // return intermediateFn

let doSomethingPartial = doSomething 1 2
doSomethingPartial 3
3 |> doSomethingPartial
[/sourcecode]

#7 Function Associativity and Composition

Function Associativity

This…

[sourcecode language=”fsharp”]
let F x y z = x y z
[/sourcecode]

…means this…

[sourcecode language=”fsharp”]
let F x y z = (x y) z
[/sourcecode]

Also three equivalent forms.

[sourcecode language=”fsharp”]
let F x y z = x (y z)
let F x y z = y z |> x
let F x y z = x <| y z
[/sourcecode]

Function Composition

Here’s an example

[sourcecode language=”fsharp”]
let f (x:int) = float x * 3.0 // f is int->float
let g (x:float) = x > 4.0 // g is float->bool
[/sourcecode]

We can create a new function h that takes the output of “f” and uses it as the input for “g”.

[sourcecode language=”fsharp”]
let h (x:int) =
let y = f(x)
g(y) // return output of g
[/sourcecode]

A much more compact way is this:

[sourcecode language=”fsharp”]
let h (x:int) = g ( f(x) ) // h is int->bool

//test
h 1
h 2
[/sourcecode]

These are notes, to read more check out the Function Composition.

______11 |> F# – Some Hackery – A String Calculator Kata

Now for some F# hacking. The first thing I did was actually go through a Code Kata, which I’ll present here.

The first step I took was to get a project started. For that I used the ProjectScaffold to build a clean project via bash.

First cloned…

[sourcecode language=”fsharp”]
git clone git@github.com:fsprojects/ProjectScaffold.git sharpKataStringCalc
[/sourcecode]

…then I navigated into the directory and executed the build.sh script…

[sourcecode language=”fsharp”]
cd sharpKataStringCalc/
./build.sh
[/sourcecode]

…then I got prompted for some input.

[sourcecode language=”bash”]
#####################################################

# Project Scaffold Init Script
# Please answer a few questions and we will generate
# two files:
#
# build.fsx This will be your build script
# docs/tools/generate.fsx This script will generate your
# documentation
#
# NOTE: Aside from the Project Name, you may leave any
# of these blank, but you will need to change the defaults
# in the generated scripts.
#

#####################################################

Project Name (used for solution/project files): sharpKataStringCalc
Summary (a short description): A code kata for the string calculator exercise.
Description (longer description used by NuGet): The code kata, kicked off my Roy Osherove, this is my iteration of it (at least my first iteration of it).
Author: Adron Hall
Tags (separated by spaces): fsharp f# code kata stringcalculator
Github User or Organization: adron
Github Project Name (leave blank to use Project Name):
[/sourcecode]

Once I hit enter after entering the information I’ve gotten more than a few of these broken builds.

[sourcecode language=”bash”]
Time Elapsed 00:00:00.1609190
Running build failed.
Error:
Building /Users/adronhall/Coderz/sharpKataStringCalc/sharpKataStringCalc.sln failed with exitcode 1.

———————————————————————
Build Time Report
———————————————————————
Target Duration
—— ——–
Clean 00:00:00.0019508
AssemblyInfo 00:00:00.0107624
Total: 00:00:00.6460652
Status: Failure
———————————————————————
1) Building /Users/adronhall/Coderz/sharpKataStringCalc/sharpKataStringCalc.sln failed with exitcode 1.
2) : /Users/adronhall/Coderz/sharpKataStringCalc/src/sharpKataStringCalc/sharpKataStringCalc.fsproj(0,0): Target named ‘Rebuild’ not found in the project.
3) : /Users/adronhall/Coderz/sharpKataStringCalc/tests/sharpKataStringCalc.Tests/sharpKataStringCalc.Tests.fsproj(0,0): /Users/adronhall/Coderz/sharpKataStringCalc/tests/sharpKataStringCalc.Tests/sharpKataStringCalc.Tests.fsproj: The required attribute "Project" in Import is empty
———————————————————————
[/sourcecode]

This problem I was able to solve once, based on what I did in a previous blog entry “That Non-Windows Scaffolding for OS-X and Linux |> I Broke It! But…“. Which seemed odd that I fixed it previously. To help with the build I actually opened it up in Xamarin Studio. Now, one of the problems with doing this, is that it’s only available on Windows & OS-X. I’m however interested in using this stuff on Linux too, but that’s looking a bit more difficult the more I work with the toolchain unfortunately.

After working through the issue I found that on one OS-X box I’d installed Mono via make and F# via make and that messes things up. Do one or the other and you should be ok. So on my other two OS-X boxes (I’ve a personal retina and a work retina) the build worked flawlessly, and when it works flawlessly it looks like this toward the end of the build execution.

[sourcecode language=”bash”]
Finished Target: GenerateReferenceDocs
Starting Target: GenerateDocs (==> GenerateReferenceDocs, GenerateReferenceDocs)
Finished Target: GenerateDocs
Starting Target: All (==> GenerateDocs)
Finished Target: All

———————————————————————
Build Time Report
———————————————————————
Target Duration
—— ——–
Clean 00:00:00.0035253
AssemblyInfo 00:00:00.0103142
Build 00:00:04.9369669
CopyBinaries 00:00:00.0052210
RunTests 00:00:00.6568475
CleanDocs 00:00:00.0025772
GenerateHelp 00:00:08.6989318
GenerateReferenceDocs 00:00:11.7627584
GenerateDocs 00:00:00.0003409
All 00:00:00.0000324
Total: 00:00:26.1162623
Status: Ok
———————————————————————
[/sourcecode]

I’ve gotten this to work on OS-X and Windows just fine using the straight up ProjectScaffold and the ./build.sh. So all is good, I’m going to move forward with writing the kata based on that and loop back around to straighten out the Linux issues.

To run the tests, execute the following script after creating the project scaffold.

[sourcecode language=”bash”]
./build.sh RunTests
[/sourcecode]

First off, what are the ideas behind the string calculator kata? Well here’s how Roy Osherove lays it out this particular code kata.

Before you start:

  • Try not to read ahead.
  • Do one task at a time. The trick is to learn to work incrementally.
  • Make sure you only test for correct inputs. there is no need to test for invalid inputs for this kata.

String Calculator

  1. Create a simple String calculator with a method int Add(string numbers)
    1. The method can take 0, 1 or 2 numbers, and will return their sum (for an empty string it will return 0) for example “” or “1” or “1 2”
    2. Start with the simplest test case of an empty string and move to 1 and two numbers
    3. Remember to solve things as simply as possible so that you force yourself to write tests you did not think about
    4. Remember to refactor after each passing test
  2. Allow the Add method to handle an unknown amount of numbers.
  3. Allow the Add method to handle new lines between numbers (instead of an empty space).
    1. the following input is ok: “1\n2 3” (will equal 6)
    2. the following input is NOT ok: “1 \n” (not need to prove it – just clarifying)
  4. Support different delimiters
    1. to change a delimiter, the beginning of the string will contain a separate line that looks like this: “//[delimiter]\n[numbers…]” for example “//;\n1;2” should return three where the default delimiter is ‘;’ .
    2. the first line is optional. all existing scenarios should still be supported
  5. Calling Add with a negative number will throw an exception “negatives not allowed” – and the negative that was passed.if there are multiple negatives, show all of them in the exception message
  6. Numbers bigger than 1000 should be ignored, so adding 2 + 1001 = 2
  7. Delimiters can be of any length with the following format: “//[delimiter]\n” for example: “//[***]\n1***2***3” should return 6
  8. Allow multiple delimiters like this: “//[delim1][delim2]\n” for example “//[*][%]\n1*2%3” should return 6.
  9. Make sure you can also handle multiple delimiters with length longer than one char.

Ok, so now that we’re clear on the string calculator, I’m going to dig into knocking out the first item, “Create a simple string calculator with a method int Add (string numbers)”

But first, in TDD fashion let’s write the test and make it fail first. I changed the code in the Tests.fs file in the tests directory and tests project to read as follows.

[sourcecode language=”fsharp”]
module sharpKataStringCalc.Tests

open System
open sharpKataStringCalc
open NUnit.Framework

[<TestFixture>]
type CalculatorTests() =
[<Test>]
member x.add_empty_string() =
let calculator = Calculator()
let result = calculator.Add ""
Assert.That(result, Is.EqualTo 0)
[/sourcecode]

That gets us a failing test, since we don’t even have any implementation yet. So now I’ll add the first part of the implementation code. First I created a Calculator.fs file and deleted the other file that ProjectScaffold put in there in the first place.

[sourcecode language=”fsharp”]
namespace sharpKataStringCalc

open System

type Calculator() =
member x.Add express =
0
[/sourcecode]

Ok, that gives me a passing test for the first phase of all this. Now since I’m a total F# newb still I’ve got to kind of dig around and read documentation while I’m working through this. So I’m taking a couple of hours while Roy’s suggestion is to use 30 minutes to do this kata. But I figured it is a good way to force myself to learn the syntax and start getting into an F# refactoring practice.

The first thing I started to do was write a test where I set the Calculator() again that looked something like this. I didn’t like that so I tried to pull it out of the test.

[sourcecode language=”fsharp”]
[<TestCase("1", Result = 1)>]
member x.Add_single_number_returns_that_number expression =
let calculator = Calculator()
calculator.Add expression
[/sourcecode]

I ended up with something like this then.

[sourcecode language=”fsharp”]
let calculator = Calculator()

[<TestFixture>]
type CalculatorTests() =
[<Test>]
member x.add_empty_string() =
let result = calculator.Add ""
Assert.That(result, Is.EqualTo 0)

[<TestCase("1", Result = 1)>]
member x.Add_single_number_returns_that_number expression =
calculator.Add expression
[/sourcecode]

After adding that code with that little refactor I ran it, red light fail, so I then moved on to implementation for this test.

[sourcecode language=”fsharp”]
type Calculator() =
member x.Add expression =
match expression with
| "" -> 0
| _ -> 1
[/sourcecode]

Everything passed. So now on to the next scenario other subsequent number strings. I add another test and result condition.

[sourcecode language=”fsharp”]
[<TestCase("1", Result = 1)>]
[<TestCase("2", Result = 2)>]
member x.Add_single_number_returns_that_number expression =
calculator.Add expression
[/sourcecode]

It runs, gets a red light fail, I then implement with this minor addition.

[sourcecode language=”fsharp”]
type Calculator() =
member x.Add expression =
match expression with
| "" -> 0
| _ -> Int32.Parse expression
[/sourcecode]

Before moving on, I’m just going to cover some of the syntax I’ve been using. The | delimits individual matches, individual discriminated union cases, and enumeration values. In this particular case I’m just using it to match the empty string or the
wildcard. Which speaking of, the _ is a wildcard match or specifies a generic parameter. To learn more about these in detail check out match expressions or generics. There are lots of good things in there.

The other syntax is somewhat more self-explanatory so I’m going to leave it as is for the moment. It is, in the end, when executing the tests evident what is going on at least. Alright, back to the kata. Let’s actually add two numbers. For the test I’m just going to add another TestCase with two actual numbers.

[sourcecode language=”fsharp”]
[<TestCase("1", Result = 1)>]
[<TestCase("2", Result = 2)>]
[<TestCase("1 2", Result = 3)>]
member x.Add_single_number_returns_that_number expression =
calculator.Add expression
[/sourcecode]

Fails, so on to implementation. I’m just going to do this the cheap “it works” way and do something dumb.

[sourcecode language=”fsharp”]
type Calculator() =
member x.Add expression =
match expression with
| "" -> 0
| _ when expression.Contains " " -> 3
| _ -> Int32.Parse expression
[/sourcecode]

That’ll give me a passing green light, but I’ll add another bit of attribute to the test and get another failing test.

[sourcecode language=”fsharp”]
[<TestCase("1", Result = 1)>]
[<TestCase("2", Result = 2)>]
[<TestCase("1 2", Result = 3)>]
[<TestCase("2 3", Result = 5)>]
member x.Add_single_number_returns_that_number expression =
calculator.Add expression
[/sourcecode]

I’ll add the following code to implement and get a passing test.

[sourcecode language=”fsharp”]
type Calculator() =
member x.Add expression =
match expression with
| "" -> 0
| _ when expression.Contains " " ->
let numbers = expression.Split [| ‘ ‘ |]
(Int32.Parse numbers.[0]) + (Int32.Parse numbers.[1])
| _ -> Int32.Parse expression
[/sourcecode]

Ok. So that part of the match looks for an empty space, and then takes the two numbers opposite sides of that empty space (array item 0 and 1) and then parses them and adds them together. Keep in mind that ‘ ‘ signifies a single character, and not a string, even though for the contains method that executes on a string, passing in a string with ” ” is ok and the appropriate actions are taken by the compiler.

For the tests I’m going to do a refactor and break them apart just a bit and rename them using the “ xyz “ technique of methods. After the refactor the code looked like this. I got this idea from the “Use F# to write unit tests with readable names” tip.

[sourcecode language=”fsharp”]
[<TestFixture>]
type CalculatorTests() =
[<Test>]
member x.“should return zero if no string value is passed in.“() =
let result = calculator.Add ""
Assert.That(result, Is.EqualTo 0)

[<TestCase("1", Result = 1)>]
[<TestCase("2", Result = 2)>]
member x.“take one number and return that number“ expression =
calculator.Add expression

[<TestCase("1 2", Result = 3)>]
[<TestCase("2 3", Result = 5)>]
member x.“add single number to single number and return sum“ expression =
calculator.Add expression
[/sourcecode]

At this point I’m going to take a break, and wrap this up in a subsequent part of this series. It’s been a fun troubleshooting and getting started string calculator kata. So stay tuned and I’ll be slinging some F# math at ya real soon.

Reference:

That Non-Windows Scaffolding for OS-X and Linux |> I Broke It! But…

I dove into the ProjectScaffold solution recently to see where I could get with this project. Just like in the instructions I first cloned the project.

[sourcecode language=”bash”]
git clone
[/sourcecode]

Then executed the shell script to get an appropriate download of Paket and related tools.

[sourcecode language=”bash”]
$ ./build.sh
[/sourcecode]

On OS-X my first attempt I got scaffolding but a bad build right off. See the video below for that example.

Trying the same thing on Ubuntu gave me this issue. This issue seemed to be different from the OS-X issue so I’m working to resolve it separately.

[sourcecode language=”bash”]
adron@ubuntu ~/C/ProjectScaffold> ./build.sh
No version specified. Downloading latest stable.
Github download failed. Try downloading Paket directly from ‘nuget.org’.
Error getting response stream (Write: The authentication or decryption has failed.): SendFailure
[/sourcecode]

Then trying it on OS-X gave me this issue.  :-/

Grumble grumble, fuss, fuss, alright, going into debugging and troubleshooting mode. I made a video of the exact steps I went through.

So if you have any ideas, let me know, I’m currently looking through the code and trying out some things. Once I get this working I’ll update this blog entry below the video with the updated resolution. Thanks!

UPDATED: Dammit, the dumbest things are what always punch me in the face the hardest. I fixed it, and it didn’t require a pull request after all! When naming a project be sure to use only string characters to be safe. As I wrote in the github issue, the name “sharp-kata-01” breaks the build in a way that gives completely erroneous messages. Once I renamed it things moved forward.