Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
sxross committed Jun 16, 2014
0 parents commit 60acc2d
Show file tree
Hide file tree
Showing 11 changed files with 307 additions and 0 deletions.
18 changes: 18 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.repl_history
build
tags
app/pixate_code.rb
resources/*.nib
resources/*.momd
resources/*.storyboardc
.DS_Store
nbproject
.redcar
#*#
*~
*.sw[po]
*.gem
.eprj
.sass-cache
.idea
.dat*.*
4 changes: 4 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
source 'https://rubygems.org'

# Define all dependencies in your .gemspec file
gemspec
16 changes: 16 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
PATH
remote: .
specs:
callback (0.1)

GEM
remote: https://rubygems.org/
specs:
rake (10.3.2)

PLATFORMS
ruby

DEPENDENCIES
callback!
rake
83 changes: 83 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# callback

Allows for multi-branch callbacks from a single method. This allows for blocks of code
to be invoked in response to asynchronous events triggered in the called method.

## Installation

Add this line to your application's Gemfile:

gem 'callback'

And then execute:

$ bundle

Or install it yourself as:

$ gem install callback

## Usage

Using `callbacks` is really easy. Just add it to your Gemfile. Then in your code do this:

```ruby
do_something_complicated do |on|
on.success {
# take actions based on success
}
on.failure {
# crash and burn gracefully
}
on.indeterminate_state {
# act really confused
}
end
```

In your `do_something_complicated` method, write code like this:

```ruby
def do_something_complicated(&block)
some_asynchronous_stuff{|status|
case status
when 'error' then block.call Callback.new(:error)
when 'success' then block.call Callback.new(:success)
when '???' then block.call Callback.new(:indeterminate_state)
end
}
end
```

A better idea of why this is interesting is code that reaches out
to a remote for asynchronously-retrieved data like this:

```ruby
check_already_logged_in do |on|
on.success{ transition_to_authenticated_user_section }
on.failure{
login do |on|
on.success{ transition_to_authenticated_user_section }
on.failure{ alert_user_to_screwup }
end
}
end
```

## Thanks To

[Emmanuel Oga](https://gist.github.com/EmmanuelOga)

and this Gist, which is essentially the entire Gem.

https://gist.github.com/EmmanuelOga/1417762

Note also [this blog post and the ensuing discussion](http://www.mattsears.com/articles/2011/11/27/ruby-blocks-as-dynamic-callbacks).

## Contributing

1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request
16 changes: 16 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
$:.unshift("/Library/RubyMotion/lib")
require 'motion/project/template/ios'
require './lib/callback'

begin
require 'bundler'
require 'motion/project/template/gem/gem_tasks'
Bundler.require
rescue LoadError
end

Motion::Project::App.setup do |app|
# Use `rake config' to see complete project settings.
app.name = 'callback'
end
5 changes: 5 additions & 0 deletions app/app_delegate.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AppDelegate
def application(application, didFinishLaunchingWithOptions:launchOptions)
true
end
end
23 changes: 23 additions & 0 deletions callback.gemspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# -*- encoding: utf-8 -*-
VERSION = "0.1"

Gem::Specification.new do |spec|
spec.name = "callback"
spec.version = VERSION
spec.authors = ["Steve Ross"]
spec.email = ["[email protected]"]
spec.description = %q{TODO: Write a gem description}
spec.summary = %q{TODO: Write a gem summary}
spec.homepage = ""
spec.license = ""

files = []
files << 'README.md'
files.concat(Dir.glob('lib/**/*.rb'))
spec.files = files
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
spec.require_paths = ["lib"]

spec.add_development_dependency "rake"
end
10 changes: 10 additions & 0 deletions lib/callback.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# encoding: utf-8

unless defined?(Motion::Project::Config)
raise "This file must be required within a RubyMotion project Rakefile."
end

lib_dir_path = File.dirname(File.expand_path(__FILE__))
Motion::Project::App.setup do |app|
app.files.unshift(Dir.glob(File.join(lib_dir_path, "project/**/*.rb")))
end
5 changes: 5 additions & 0 deletions lib/project/callback.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Callback = Struct.new(:called, :args) do
def method_missing(name, *)
name == :"#{called}?" || (name == called && block_given? && yield(*args))
end
end
Binary file added resources/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
127 changes: 127 additions & 0 deletions spec/callback_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
class ThingWithCallbacks
def succeeder(arg1, arg2, &block)
if arg1 == 'hello'
yield Callback.new(:success, 'success')
else
yield Callback.new(:failure, 'failure')
end
end
end

class ThingWithClassLevelCallbacks
class << self
def succeeder(arg1, arg2, &block)
if arg1 == 'hello'
yield Callback.new(:success, 'success')
else
yield Callback.new(:failure, 'failure')
end
end

def fxn_with_no_args(&block)
yield Callback.new(:success, 'success')
end
end
end

describe 'Callback' do
before do
@thing = ThingWithCallbacks.new
end

describe "provides for success and failure callbacks" do
it "success" do
result = nil
@thing.succeeder 'hello', 'world' do |on|
on.success {|value| result = value}
end
result.should == 'success'
end

it "failure" do
result = nil
@thing.succeeder 'goodbye', 'world' do |on|
on.failure {|value| result = value}
end
result.should == 'failure'
end

describe "multibranch" do
before do
@success_val = 'unmodified'
@failure_val = 'unmodified'
end

it "success case" do
@thing.succeeder 'hello', 'world' do |on|
on.success {|value| @success_val = value}
on.failure {|value| @failure_val = value}
end
@success_val.should == 'success'
@failure_val.should == 'unmodified'
end

it "failure case" do
@thing.succeeder 'goodbye', 'world' do |on|
on.success {|value| @success_val = value}
on.failure {|value| @failure_val = value}
end
@success_val.should == 'unmodified'
@failure_val.should == 'failure'
end
end

end
end

describe 'Class level callbacks' do
describe "provides for success and failure callbacks" do
it "success" do
result = nil
ThingWithClassLevelCallbacks.succeeder 'hello', 'world' do |on|
on.success {|value| result = value}
end
result.should == 'success'
end

it "failure" do
result = nil
ThingWithClassLevelCallbacks.succeeder 'goodbye', 'world' do |on|
on.failure {|value| result = value}
end
result.should == 'failure'
end

describe "multibranch" do
before do
@success_val = 'unmodified'
@failure_val = 'unmodified'
end

it "success case" do
ThingWithClassLevelCallbacks.succeeder 'hello', 'world' do |on|
on.success {|value| @success_val = value}
on.failure {|value| @failure_val = value}
end
@success_val.should == 'success'
@failure_val.should == 'unmodified'
end

it "failure case" do
ThingWithClassLevelCallbacks.succeeder 'goodbye', 'world' do |on|
on.success {|value| @success_val = value}
on.failure {|value| @failure_val = value}
end
@success_val.should == 'unmodified'
@failure_val.should == 'failure'
end
end

it "works with a function that takes no arguments" do
ThingWithClassLevelCallbacks.fxn_with_no_args do |on|
on.success {|value| @success_val = value}
@success_val.should == 'success'
end
end
end
end

0 comments on commit 60acc2d

Please sign in to comment.