Wednesday, August 22, 2012

Dubbcasts: Episode 4 - Supertab and Snipmate Working Together


A demo of the popular Supertab and Snipmate vim plugins working together. These two tend to both compete for the Tab key and end up getting in each other's way. By overriding a simple global setting, they'll play nice together again. Enjoy.

Sunday, August 19, 2012

Dubbcasts: Episode 3 - Vagrant

In this episode I cover using Vagrant for everyday development and how it can allow you to keep your primary development machine free of third party dependencies and the remnants of experimental usage. There's really no source code associate with this post but I am making use of Ubuntu and Mongodb. I didn't bother uploading anything to Github this time around seeing as how I'm not specifically covering these topics. I'd also highly recommend you take a look at Deploying Rails over on Pragprog. Enjoy.

No Sound After Suspend/Sleep Mode Mac OS X

The Problem

So this problem has been a thorn in my side for months now. It's really annoying because the only way you can get your sound back is with a full reboot. No one was to be preempted with a reluctant reboot every time they put their computer to sleep, so enough already! It took me a while to find possible solutions to this problem but after some persistent googling, I was able to track down a helpful post on the Apple Support forum. There are a few recommended solutions I was able to glean from the thread.

 1. Disk Utility's Repair Disk Permissions feature

This post explains this feature. I've included a screenshot below of the app (Applications/Utilities/Disk Utility.app).





























I don't know if this really helps, but I did it anyway and it definitely doesn't hurt. I'd recommend this one as some permissions are bound to be out of synch and who knows what side affects they could be causing.

2. Plug Headphones In/Out

Sounds like a hack, right? Well apparently this has worked for some people but it's certainly not a long term solution. Put in your favorite earbuds, take them back out, and be blessed with audio. I've yet to try this technique as I find success via the command line but feel free to cross your fingers and give it a shot.

3. Uninstall Parallels Desktop

"Not I said the cat". 

I don't know how feasible this one is but someone managed to link the problem to Parallels Desktop. If you've ever saw one of my screencasts you'll know that's virtualization software for Windows and other operating systems. I'm not planning to uninstall software I payed 100 bucks for, but if you want your audio back and have some other VM you can run then knock yourself out.

4. Restore your OS

This isn't particular good but assuming you have a TimeMachine backup or fully backed up image on hand then I guess it's not too bad. If you've got the time to spare then a clean restore could turn out to pay dividends. I don't think I'll be doing this until my Lion is old, immobile, and children have graduated to the big leagues capable of hunting on their own and tracking down their own prey. I do have backups in place but I'd rather not have to make use of them anytime soon.

5. Reset Permissions on coreaudiod.plist

These are permissions related to the coreaudio daemon process that's spawned by the OS. This can be accomplished with a simple command line.

sudo chown root:wheel /System/Library/LaunchDaemons/com.apple.audio.coreaudiod.plist

I tried navigating to that path in my shell but it didn't resolve. Maybe it's under a different alias in later versions of Mac. If you're able to locate it then good luck.

6. Set KeepAlive to "True" in coreaudiod.plist

This involves editing the contents of "com.apple.audio.coreaudiod.plist"

<key>KeepAlive</key>
       <true/>

7. Kill/Restart the coreaudio daemon

This one worked for me!!

Simply execute this command from your shell.

sudo kill -9 `ps ax|grep 'coreaudio[a-z]' |awk '{print $1}'`

I've created a script with the contents of the command and placed it in "/usr/local/bin". Make sure that location is included in your path. After creating the file, be sure to make it executable with

chmod 755 <whatever_you_named_the_script>

What you may notice after executing this command is that the OS was queueing up all your audio  requests in the background. You'll here it flushing it's internal buffer and your speakers getting flooded with audio from the moment your computer was summoned from sleep mode up until the time you restarted the coreaudio daemon. So if you pressed the volume button 12 times, you'll here 12 little "pops" synchronously pumped out of your speakers. It's like cleansing your system after years of build up. It all just comes out at once. Hehe :)

The End

I'll admit that none of the solutions are particularly "clean", but they're better than having to use preferences to increase your volume and being robbed of the spoils of devices like Apple Remote. Apple is undoubtedly long overdue for a patch as this seems to have been a problem for at least over a year now. I hope one of these tips works for you, and as always, feel free to refer directly to the forums for additional help, additional clarity, or any solution I may have failed to extract and make known.

Tuesday, August 14, 2012

Dubbcasts: Episode 2 - One Transaction Per Request (Uow)

A follow up and more concrete example from Episode 1, this is a demo of how to implement one transaction per request (Unit of Work) in an ASP.NET web application using NHibernate and Autofac. I kinda screwed up the audio again. Sorry about that and I'll get it right next time. Thanks and enjoy.


Monday, August 13, 2012

Dubbcasts: Episode 1 - NHibernate Performance Tip


A demo that simulates using the Unit of Work pattern; more specifically, a single database transaction per request. This is my first screencast and it turned out to be a lot more work that I thought. It's pretty long, over an hour, but to spare you all the debugging, hacking, and gory details, I've posted the source code on Github so you can run the sample for yourself.

The screencast is laced with beats from some of my favorite songs. I had no choice since I screwed up the audio while I was recording. It was full of static/background noise and you could hardly make out one word from the next. So there you have it...the birth of Dubbcasts. May this be a day to remember for years to come.

Sunday, August 12, 2012

An Interesting Observation About the Google Search Algorithm

In my never ending quest to make my vim editor as perfect as it can be, I was doing a quick query to determine if exuberant ctags had the ability to interrogate tag files in distinct locations, or if it needed all tags to be present in one huge gargantuan tag file.

So I did a quick search in Google:

"aggregate tags vim exuberant ctags"

I found a pretty interesting article with tons of helpful information in it. After scanning though it, I think I was convinced I had the answer I was looking for. But then for some strange reason, curiosity made an impromptu appearance and asked a sequence of two very simple questions...

"Does this document even contain the word aggregate? Why is it ranked so high relative to this query?"

So I thought about it and did a quick search in Chrome (Command + F on Mac), and to my surprise, the word aggregate was nowhere to be found. Want to guess what I found instead? Words that make up the definition of the word aggregate, or are similar to words that do so. Words like "one", "big", "global",  "all", etc.

Based on these results, I could only conclude the following...

Google's search algorithm will not only literally search for a word contained within a document, it will also search for words contained within the definition of that word.

Not that I care what the realists of the world think, but I'm sure (as many may point out when coming across this post) this information is publicly available somewhere and probably no secret to the search experts of the world. That being said, I don't spend a ton of time analyzing the idiosyncrasies of the Google Search algorithm. So yes, I did ignorantly go out of my way to write this post irrespective of the aforementioned givens. I'll bet you there are thousands more that aren't even aware that this feature is potentially embedded within Google Search, and at least they'll get a quick glimpse of it all upon hitting this blog. Naturally deriving something is something I've always viewed as an accomplishment; even if someone else has already done so. It always feels good, and it feels even better when you can blog about it.

At any rate, neat stuff by Google, and pretty cool on top of that.

Tuesday, August 7, 2012

You Lost Your Wallet - Flying with No ID, Credit Cards, etc.


If You've Lost Your Wallet, File a Police Report


I took for granted how much a police report could help you in a situation like this. It's one of the
initial questions the Airtran employee asked me. She was so serious about the police report that she
insisted I go file one with the local authorities at the airport. Lucky for me, they were unavailable
due to how early in the morning it was. I walked back through the double doors with a concerned look on my face; the look of a lost child. Once I heard her summon me back to the kiosk, I knew I'd caught a break. She made several phone calls to headquarters to ensure I could still fly under the circumstances. After receiving an ear full about why I should have filed the police report, her being intermittently put on hold for extended periods of time, and me putting on my best impression of a stranded adolescent, I was good to go. Sandra, the Airtran employee that so diligently worked to get me on my flight back to Washington, was also kind enough to let me know that I'd go through additional screening once I encroached the security checkpoint. If you've flown before, you know that getting past the front counter is only half the battle. Three letters...TSA. I got the same question once I made it to the security checkpoint. "Do you have a police report sir?". It was then that I realized how much of a burden it would have removed from the entire process.

So why didn't I file that report right off the bat? Don't ask....

The Social Security Number is a Lie


If you're trying to fly with no identification, at no point should anyone request your social security number (not even the last for digits). Not TSA, not whomever you booked your flight with, not anyone. I was eager to give out my number in some form or fashion. Whatever it took for me to prove that I'm Antwan Wimberly. I just knew someone would ask me for it. And to my surprise, no one did. They've got other means of verifying your identity. Knowing this up front can alleviate that much more pressure.

Documents with your Name on them will Help


In addition to numerous questions that you'll be hit with by TSA, believe it or not, they actually want to see you fly. They'll try and work with you. The officer asked me did I have any documents with my name on them. I immediately replied with "no", assuming she meant something issued by a public authority. But TSA uses the term documents loosely. It can be anything. A receipt, an old boarding pass, whatever you can show them. So don't be shy when it comes to filtering through you backpack for anything you can find with your name on it. The more, the better.

Be Prepared for Additional Questions and Screening by TSA


Did you think it'd be that easy? Haha..not quite. You'll be hit with numerous questions before they allow you to proceed to your final destination. I won't cover the questions here due to security reasons, but you'll be able to trivially answer them if you are indeed who you say you are. You'll have to fill out a form stating that you're aware that providing false information is a crime. It wont' take you long at all. Once you're done with the form and answering any questions TSA has for you, they'll send you through for additional screening along with the normal protocol (body scan,  putting your items on the conveyer belt, etc.). Don't be frightened by the term additional screening. All it means is that they'll physically pat you down as a precautionary measure. They'll also take samples from anything you're carrying (shoes, backpack, etc.) and run it through a database. It's not that bad though. You should be on your way in no time.

Get There Early


You'll want to arrive to the airport at least 2 hours early. You'll need the extra buffer to account for the additional questioning and screening that you'll be exposed to. So don't get careless and show up an hour before your flight thinking that everything is going to go smoothly. You should expect a hiccup or two and have enough time to recover.

Be Polite


The last thing you want to do is piss someone off. They want to help you, but giving a reason not to do so could result in you missing your flight. These people will have to make phone go and take additional measures to ensure that you can fly. They're working a lot harder than they're used to, and all they want is to be appreciated. If you feel like they're giving you a hard time or your being bombarded with tons of questions, don't panic. Keep your cool and push your ego to the side. They can't make it look like flying without an id isn't frowned upon or won't be met with resistance. How much they sale this depends on their personality. Sandra was pretty tough to start out with, but she eventually loosened up and hopped on the phone for me. As I mentioned earlier, she was even convinced that I should show them a police report. Just know that they'll come around. Express concern and gratitude. I'm not saying that you have to suck up or kiss anyone's ass, but be careful about pushing back once the storm of interrogatives commences.

A Checked Bag will Mike Life a Little Harder


You want to know what made Sandra as upset as she was? The fact that I was trying to check a bag. I always fly with luggage, because I want to be comfortable when I travel and I hate wearing the same clothes over and over. That's just me. But this pesky habit almost lead to my demise. It made things more nuanced than they had to be. That extra wrinkle is what initiated the phone calls and all the waiting up front. She kept saying over and over that the fact that I had a checked bag was what she had a problem with. It wasn't aimed directly at me but was more so her thinking out loud. She knew I'd introduced more complexity and that she'd have to be the one to sort it all out. I'm not saying that you should blindly leave your luggage behind, but if you don't have any, then it'll probably expedite the process.

The Myths About Costco Cards are True


I was reading an article that mentioned that TSA would accept Costco cards as valid authentication since it has your photo ID on it. Costco isn't as trusted an authority as the DMV, but it can help you get through TSA. I heard the officer that was helping me ask another guy if he had a Costco card. I may have also even heard SAM's Club (I definitely heard it if they embed your photo onto your card like Costco does).

Cards in General Help as Well


This may be a no brainer, but Debit cards, credit cards, and others can also help you. TSA inquired about one and so did Sandra of Airtran. My only problem was that I'd lost EVERYTHING in one go. So no social security card, debit card, credit cards, etc. If you happen to have these things then you'll be much better off.

Be Careful About Curbside Checkin


The primary risk here is that well...you may get things out of synch. I don't exactly know how curbside checkin works, but from what I can tell you can get your boarding pass online. In theory you could go directly to TSA/security checkpoint. Say for instance you check your bags curbside but get rejected at the security checkpoint. All in all I think you'll be fine. But Delta did send my bags to Jacksonville when I clearly changed my flight to go to Atlanta. I was initially going there until I found out my grandmother was headed into the city. So I figured why not change? Next thing you know I've taken 2 trips to Duval over a span of like 5 hours. It was pretty hectic. This could no doubt be advantageous to you as you'll have one less dependency being able to bypass the guys at the front counter but at the same time you could be asking for it.

Courtesy of http://www.jaunted.com/
















That's all folks...

Synching Your Vim Configuration Files to Dropbox on Change OS X

If you're a user of Vim of any kind of experience level, you've probably come across vimrc and gvimrc. Your experience with vim is heavily ties to these 2 files, hence the need to have them backed up in a safe place in case anything catastrophic manages to occur on your system. Specifically I've implemented a tiny but useful script to push my most precious vim assets to my Dropbox account in the ever so beloved and mysterious....."cloud".

I haven't tested this on Windows as I don't make many changes to my vim configuration on my win32 computer. I find it more effective to manually synch those changes not to mention I don't use vim nearly as much on win32 as I do on darwin (OS X).

That was kind of a joke btw. If you look closely enough you'll see why this won't work on win32 out of the box without a bit of magic or aliasing. Maybe powershell exposes an alias for the command I'm using in the same way that it maps "ls" to "dir", but anyway.

So here goes...

" Synch vim files to dropbox on change
:augroup VimFiles

autocmd! VimFiles BufWritePost ~/.vimrc :!cp ~/.vimrc $HOME/Dropbox/vimrc
autocmd! VimFiles BufWritePost ~/.vimrc.local :!cp ~/.vimrc $HOME/Dropbox/vimrclocal
I've place the snippet above in my .vimrc.local config. What's vimrc.local? Well, there are some "vim bootstraps" out on the market and Steve Francia's is a pretty good option. His vim bootraps process will source the vimrc.local dotfile from vimrc. This allows you to override or customize the bootstappers default configuration without directly changing its contents (vimrc). This is important because the bootstrapper takes the form of a git repo which allows you to pull in updates. You can imagine your changes conflicting with the author's and all other kinds of hairy predicaments version control systems lend themselves susceptible to.

You'll also notice the usage of the augroup vim command. This is just a neat way to organize your vent subscriptions. Vim can keep track of these and manage them as a whole. For example, you could delete all event subscriptions under a particular group if you wanted to. Just handy namespacing. These groups are optional so you should use them at your convenience.

If the :! syntax is news to you then it's just a way to spin up your local shell (cmd, bash, zsh, etc.) and execute an arbitrary command. The same as backticks/sh/system in Ruby, Exec task in msbuild, etc.

As far as gvimrc goes, I don't have much use for one since I use MacVim. I'm perfectly content with my vim GUI and to be honest my system doesn't even contain a gvimrc dotfile. The two files I care most about are covered.

Now I know this script is way simple, it's only 2 lines for crying out loud, but exactly what is it doing?
The vim runtime publishes events that developers can conveniently subscribe to. These events range anywhere from when vim first loads to when a file changes on your file system outside of the context of vim. There are a multitude of these events wich a varying degree of scope and granularity. To see a full list, just invoke the vim help with "au" as an argument.
:h au
au is an ancillary/alias for autocmd so of course either will suffice.

The event I'm subscribing to is the BufWritePost event. And quote...

"after writing the whole buffer to a file"

Most all the events take a regex pattern as input so you can handles multiple files, check based on extension, etc. For example, the vim runtime doesn't know about well known file names idiomatic to Ruby such as

Rakefile - searched for and loaded by rake by default
config.ru - rack configuration for rack based apps like Rails and sinatra
Capfile - capistrano configuration for deployments

etc...

So I took time out to tell vim that it should treat these files as Ruby code so I could get syntax highlighting. Otherwise they just read as plain text and that's quite the inconvenience for today's developer. We Mac users love our aesthetically pleasing things so the more color the better *wink*.
:augroup UnrecognizedRubyFiles

" Set file type to Ruby for unrecognized ruby files
autocmd! UnrecognizedRubyFiles BufReadPost,FileReadPost Gemfile,Rakefile,config.ru,Thorfile,Capfile,Vagrantfile set ft=ruby

The BufReadPost event is published once vim finishes reading your file. Not a bad time to tell it what we're working with. You could probably even get away with subscribing to an event published earlier in the runtime but this works for me.

Well, that's pretty much it folks. We took a look at subscribing to vim event via the au/autocmd command. Again, this command is nice because it can accept patterns as arguments. We can also namespace our event subscriptions with the augroup command. You'll see this technique employed by many plugin developers. Take rails.vim for example.

























Thanks guys...enjoy.

Saturday, April 7, 2012

Using Set Theory, Ruby, and Map/Reduce to Implement Portable Class Libraries Feature in VS 11


How it all started...

I crunk up my Mac and began perusing the web.

Checked out a pretty nice article from my man Thomas P on joinads.

Man was I craving some F#.

I had to show my usual love...you know..Tweet dat and +1 dat!!

Once I got over to the Googleplex I began to scroll my feed.

Came across my man Hanselman and decided to check out the hype with a new feature coming in VS 11.

It's this multi targeting guy that allows you to implement an assembly that can be deployed across multiple Microsoft Platforms (Xbox, Silverlight, etc.)

So what does this mean?

Well...let's take Silverlight for example.

It's a subset of the CLR and .NET Framework so certain libraries available in say...an MVC app wouldn't be available in Silverlight.

So VS would proceed to remove those libraries that can't be used across both platforms.

So you're basically at the mercy of the platform that can support the least amount of libraries. You're only as strong as your weakest link, right?

Lets take an example

say we have the following platforms

Silverlight = [a, b, c]
MVC = [a, b, c, d]
Xbox = [a, b, c, d, e]

What's the expected output?

Easy...everything in Silverlight!!

[a, b, c]

It can only support libraries a, b, and c.

MVC and Xbox can also support d and e, but they're SOL here b/c their little sister can't hold her liquor.

Sorry Orteguitas...life isn't fair...

What would I expect in a comparison of MVC and Xbox?

[a, b, c, d]...

Ok..I think you get it by now, right?

I've said all that to say this...what if you had to implement this logic?

What would you do?

How many lines of code do you think it would take?

These are questions that I'm always pondering.

It's like..."Hey Antwan, what if LCD tv'S didn't exist and you had to be
the guy to implement them?"

A chin rub and shot of Gatorade later and I'm off to the races..

Haha..sike...I eventually embrace the reality of it all and reluctantly tell my brain that there's noway I'd have been able to make electricity, the first airplane or even the world's first LCD tv...ha..I wish.

But programming is something that I've managed to become pretty good at..and that
my friends...means there's hope.

So what if I had to implement this feature in VS?

Well...I spent a few minutes thinking it over and I came right back to the very foundations of our profession and the bit munching concoction of semiconductors, circuitry, and hardware that we hold so dear to our hearts...math!!

Wait...I'm having a flash back...discrete mathematics from college...oh no..the pain..the horror..is that a turing machine? I'm having a mental aneurysm...

Ok...back to the show..

It's simple set theory if you think about it.

Take the intersection of all the sets..and well...you're done.

We've already implemented this very scenario...at least at a high level..
now lets get into some code..

I couldn't decided whether I'd do this guy in Ruby, C#, or F#...cuz as we all know...loops are just my thing. Enumerable - Enumerable - Enumerable!!

All 3 languages provide pretty sweet implementations of Enumerable...but I've yet to publish any content in Ruby...so here goes.

We'll start out with some tests and then work our way to the final implementation.

Off the top of my head...I know that LINQ provides a native implementation of intersect, but not sure about Ruby...a quick Google aaaaaaand...

Drum role please...

Bam!!

Found it...

Here's the syntax

ary & other_ary → new_ary

we're golden.

Before we get started, I just want to take a brief moment to highlight our plan of attack.

We're going to use aggregation here..you know..take 2 values, generate a result, and push that result through the pipeline as new state to be combined with the next element of our sequence (acculamators).

This concept if the basis of Sum, Product, etc...

so something like

[ 1, 2, 3, 4, 5 ].inject(:+) # => 15

in Ruby..

What inject is doing here is enumerating the sequence, taking 2 values at a time,
adding them together, and returning a new value to be added.

So it goes

Iteration    Seed    CurrentValue

1               1          2
2 3          3
3 6          4
4 10         5

done...break loop

15 is our final answer..

Make sense?

The cool thing about inject is that you can abstractly pass any "function" to it and have that function applied to all elements in your sequence.

We could multiply all numbers if we wanted

[1,3,5,7].inject(:*) # => 105

What you're seeing is a shorthand syntax to inject.

In it's more explicitly form you'd do something like

[1,3,5,7].inject(0) {|sum, element| sum+element}         # => 16
[1,3,5,7].inject(1) {|product, element| product*element} # => 105

passing in a block.

We're using the more succinct shorthand syntax...gotta love that MRI sugar, yea?

I've covered this kinda thing in F# in a previous blog post..so nothing new..jus thought I'd share that again since it's such an essential and rudimentary concept.

I puts quotes around the word "function" up above because this is merely functional programming. I've managed to pick up a lot about in through F#, C# (LINQ), and a variety of other sources over the years. It'd only behoove you as a developer to pick up a functional language at some point during your career. So much of the very code that you write on a daily basis can be tied back to functional programming; and that implicit marriage feels even better once one gets to that point that he/she can explicitly detect it. Everything just starts to make sense.

Ok, I digress.

Didn't I say we'd get into some code? Oh yea...right..just didn't wanna leave anyone behind. I'm sure
the average dev that comes across this post will have jumped to the source by the time they got past
paragraph 2..haha.

If you'd like to see more of those cool Ruby samples I posted above, just checkout the Pickaxe Book. All those samples come straight from that book verbatim. A great read for any novice Ruby dev such as myself and even for the most experienced of Rubyists.

Ok so lets get started.

I'll start with a class to track our library instances and a stub implementation to detect compatibility.

platform.rb

class Platform

    attr_reader :name, :libraries

    def initialize(name, libraries)
        @name = name
        @libraries = libraries
    end
end

portable_class_lib.rb

require './platform'

module PortablePlatform
    def PortablePlatform.get_compatible_libraries(platforms)
    end
end
We'll keep this guy short and sweet...just a few test cases.

portable_platform_lib_tests.rb

require './portable_class_lib'
require 'test/unit'

class TestPortableClassLib < Test::Unit::TestCase
    def test_3_platforms_with_3_common_libraries
        xbox_libraries = %w{ System System.Web.Mvc System.ServiceModel System.Runtime.Serialization }
        xbox = Platform.new('Xbox', xbox_libraries)    

        silverlight_libraries = %w{ System System.ServiceModel System.Web.Mvc }
        silverlight = Platform.new('Silverlight', silverlight_libraries)

        mvc_libraries = %w{ System System.Web.Mvc Mvc.Core System.ServiceModel }
        mvc = Platform.new('ASP.NET MVC', mvc_libraries)

        platforms = [xbox, silverlight, mvc]

        compatible_libraries = PortablePlatform::get_compatible_libraries(platforms)

        expected_output = %w{ System System.ServiceModel System.Web.Mvc }

        assert_equal(expected_output, compatible_libraries)
    end

    def test_3_platforms_with_2_common_libraries
        xbox_libraries = %w{ System System.Web.Mvc System.ServiceModel System.Runtime.Serialization }
        xbox = Platform.new('Xbox', xbox_libraries)    

        silverlight_libraries = %w{ System System.ServiceModel }
        silverlight = Platform.new('Silverlight', silverlight_libraries)

        mvc_libraries = %w{ System System.Web.Mvc Mvc.Core System.ServiceModel }
        mvc = Platform.new('ASP.NET MVC', mvc_libraries)

        platforms = [xbox, silverlight, mvc]

        compatible_libraries = PortablePlatform::get_compatible_libraries(platforms)

        expected_output = %w{ System System.ServiceModel }

        assert_equal(expected_output, compatible_libraries)
    end

    def test_3_platforms_with_no_common_libraries
        xbox_libraries = %w{ System.Runtime.Serialization }
        xbox = Platform.new('Xbox', xbox_libraries)    

        silverlight_libraries = %w{ System }
        silverlight = Platform.new('Silverlight', silverlight_libraries)

        mvc_libraries = %w{ System.ServiceModel }
        mvc = Platform.new('ASP.NET MVC', mvc_libraries)

        platforms = [xbox, silverlight, mvc]

        compatible_libraries = PortablePlatform::get_compatible_libraries(platforms)

        assert_empty(compatible_libraries)
    end
end

And the test results...

Run options: 

# Running tests:

FFF

Finished tests in 0.001343s, 2233.8049 tests/s, 2233.8049 assertions/s.

  1) Failure:
test_3_platforms_with_2_common_libraries(TestPortableClassLib) [-:40]:
<["System", "System.ServiceModel"]> expected but was
<nil>.

  2) Failure:
test_3_platforms_with_3_common_libraries(TestPortableClassLib) [-:21]:
<["System", "System.ServiceModel", "System.Web.Mvc"]> expected but was
<nil>.

  3) Failure:
test_3_platforms_with_no_common_libraries(TestPortableClassLib) [-:57]:
Expected nil (NilClass) to respond to #empty?.

3 tests, 3 assertions, 3 failures, 0 errors, 0 skips

Failures just as we suspected. Lets plug in an implementation, shall we?

require './platform'

module PortablePlatform
    def PortablePlatform.get_compatible_libraries(platforms)
        platform_names = []

        platform_libraries = platforms.collect do |p|
            platform_names << p.name # go ahead and cache the names so we don't loop twice
            p.libraries # retrieve all libraries
        end

        compatible_libraries = platform_libraries.inject(:&)
        libraries_sorted_by_name = compatible_libraries.sort

        puts "Platforms...\n\n"

        platform_names.sort.each { |name| puts name }

        unless compatible_libraries.any?
            puts "\nHave no common libraries."
            puts "\nUnfortunately you cannot create a portable class library targeting these platforms."

            return libraries_sorted_by_name
        end

        puts "\nHave the following libraries in common...\n\n"

        libraries_sorted_by_name.each { |name| puts name }

        puts "\nTo make a portable class library, you'll need to reference these assemblies."

        libraries_sorted_by_name
    end
end

And now after re-running the tests we get...

Run options: 

# Running tests:

Platforms...

ASP.NET MVC
Silverlight
Xbox

Have the following libraries in common...

System
System.ServiceModel

To make a portable class library, you'll need to reference these assemblies.
.Platforms...

ASP.NET MVC
Silverlight
Xbox

Have the following libraries in common...

System
System.ServiceModel
System.Web.Mvc

To make a portable class library, you'll need to reference these assemblies.
.Platforms...

ASP.NET MVC
Silverlight
Xbox

Have no common libraries.

Unfortunately you cannot create a portable class library targeting these platforms.
.

Finished tests in 0.000913s, 3285.8708 tests/s, 3285.8708 assertions/s.

3 tests, 3 assertions, 0 failures, 0 errors, 0 skips

We're golden!!

So how'd it work? Well, lets take our core algorithm (minus all the output) and our first test case.

def PortablePlatform.get_compatible_libraries(platforms)
    platform_names = []

    platform_libraries = platforms.collect do |p|
        platform_names << p.name # go ahead and cache the names so we don't loop twice
        p.libraries # retrieve all libraries
    end

    compatible_libraries = platform_libraries.inject(:&)
    libraries_sorted_by_name = compatible_libraries.sort
end

def test_3_platforms_with_3_common_libraries
    xbox_libraries = %w{ System System.Web.Mvc System.ServiceModel System.Runtime.Serialization }
    xbox = Platform.new('Xbox', xbox_libraries)    

    silverlight_libraries = %w{ System System.ServiceModel System.Web.Mvc }
    silverlight = Platform.new('Silverlight', silverlight_libraries)

    mvc_libraries = %w{ System System.Web.Mvc Mvc.Core System.ServiceModel }
    mvc = Platform.new('ASP.NET MVC', mvc_libraries)

    platforms = [xbox, silverlight, mvc]

    compatible_libraries = PortablePlatform::get_compatible_libraries(platforms)

    expected_output = %w{ System System.ServiceModel System.Web.Mvc }

    assert_equal(expected_output, compatible_libraries)
end

We started out by storing the names of all platforms in an array in addition to retrieving the actual libraries for each platform. As you may already know, collect is the equivalent of map from a functional perspective.

Now for the set manipulation. Remember when we looked up that intersect syntax a while back?

ary & other_ary → new_ary

Well...we used it here for each set of libraries.

First we intersected the set of xbox libraries with itself, which of course just returned the original set of xbox libraries.

[ System, System.Web.Mvc, System.ServiceModel, System.Runtime.Serialization ]

Then that we took everything the xbox libraries and the silverlight libraries had in common. That yielded

[ System, System.Web.Mvc, System.ServiceModel ]

Finally we were left with the MVC libraries. That intersection yielded...well...the same thing

[ System, System.Web.Mvc, System.ServiceModel ]

Done!!

There's that inject function from earlier when we summed up all our numbers. That aggregate/bulk function that I'm always raving about. We applied it to each set of libraries using the intersect operator as our function. It should be obvious by now that when you use inject you'll be dealing with a generic scenario...

let a = a set of values of type b
let s the seed = the first element of a ,or a value of type b
let f = a function that accepts 2 elements of type b and returns a new element of type b
let o the output = a new element of type b

So basically you start with a sequence of values and end up with one. Sum takes a sequence of numbers and returns an individual number as the result. Just like our algorithm takes a sequence of arrays and returns an individual array as a result. This concept is known as reduce in the functional world. We actually used both map and reduce here...didn't we? Sound familiar? We mapped the platforms to a sequence of arrays, and reduced that sequence of arrays down into an individual one.

I've covered map/reduce before but it's shown up yet again. What a coincidence...

I'd like to take this time to conclude my post...

Shout out to Alicia G in the Show Me...

And I can't leave without giving you a glimpse of my exotic and elaborate lady friend that allowed me to pull off such an amazing feat. Her beauty and elegance are second to none. A hue and texture so rare. Her movements equivalent to the speed and grace of a Cheetah...my dear lady..where would I be without you?

Ladies and gentlemen....Vim

Mac Vim


Duces...













oink oink!!