motion-kit-events 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +119 -0
- data/lib/motion-kit-events/layout.rb +45 -0
- data/lib/motion-kit-events/version.rb +5 -0
- data/lib/motion-kit-events.rb +23 -0
- data/spec/ios/events_spec.rb +16 -0
- metadata +79 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1dff0c162d7aa79745f3688409745e9a096b5af0
|
4
|
+
data.tar.gz: 9e8bc6302c39eb7c3fa2ee82a2f2e3c42221fda7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4bfcebe914349985e9d232779761fa8d579058daf73f76d1912a54d6ee1e5a8174524cc9d6bea87dd3a90c6f1ffb2c679530b5d86d63dc45d7cd67b1be32bfda
|
7
|
+
data.tar.gz: 8ce463671100d3867c42658b3f10def5192a461eb6df7cb9e3873ffcd863273b157eee5597ab4d741b76ff56b6e811e054b5756cca37102406a7e370fe0b6ee7
|
data/README.md
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
MotionKit::Events
|
2
|
+
--------
|
3
|
+
|
4
|
+
In an effort to encourage even MORE separation of concerns in your Controllers
|
5
|
+
and Layouts, the `motion-kit-events` gem provides a very way to emit generic
|
6
|
+
events from your layout that you can respond to in your controller.
|
7
|
+
|
8
|
+
## LoginController
|
9
|
+
|
10
|
+
An example of a UIViewController using MotionKit::Events:
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
class LoginController < UIViewController
|
14
|
+
|
15
|
+
def loadView
|
16
|
+
@layout = LoginLayout.new
|
17
|
+
self.view = @layout.view
|
18
|
+
|
19
|
+
@layout.on :login do |username, password|
|
20
|
+
@layout.pause_ui
|
21
|
+
# send login info to the API (I would recommend using a separate class
|
22
|
+
# to handle the API conversation, e.g. a LoginStorage class).
|
23
|
+
storage.login(username, password) do |user, errors|
|
24
|
+
handle_login(user, errors)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def storage
|
30
|
+
@storage ||= LoginStorage.new
|
31
|
+
end
|
32
|
+
|
33
|
+
def handle_login(user, errors)
|
34
|
+
# ...
|
35
|
+
@layout.resume_ui
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
```
|
40
|
+
|
41
|
+
Before we go on to show the `LoginLayout`, consider for a second how *easy* it
|
42
|
+
would be to write specs for a controller like this. We don't need to test the
|
43
|
+
UI (that will be done in isolation, using the `LoginLayout`) and our controller
|
44
|
+
doesn't directly send any *requests*, so we can assign it (in our specs) a
|
45
|
+
`TestLoginLayout` class as the storage, which can imitate the behaviors we are
|
46
|
+
interested in. We should also use a fake layout class in there, too.
|
47
|
+
|
48
|
+
TL;DR: we can test just the behavior of the controller. When it receives a
|
49
|
+
`:login` event, it should send a `login` request to its storage, and handle
|
50
|
+
`user` or `errors`.
|
51
|
+
|
52
|
+
|
53
|
+
## LoginLayout
|
54
|
+
|
55
|
+
We send the `:login` event along with the username and password when the user
|
56
|
+
presses the login button or presses "Return" from the password field. This is
|
57
|
+
all code that would normally be in the UIViewController. The tight coupling of
|
58
|
+
the UIViewController and the UI is very common in iOS apps, but there is much to
|
59
|
+
be gained be decoupling these roles. The Controller can focus on the *movement*
|
60
|
+
of the user.
|
61
|
+
|
62
|
+
The user starts out in a "logging in" state. Until they submit credentials, the
|
63
|
+
controller need not be interested in what the UI is doing to accomodate this
|
64
|
+
procedure. It just cares about when the user is *done*, and it pauses the UI.
|
65
|
+
|
66
|
+
When the login attempt is complete, the controller tells the UI what state to go
|
67
|
+
in next, either resuming the UI if an error occurred, or just dimissing the
|
68
|
+
controller and passing along the successful login info.
|
69
|
+
|
70
|
+
If you look at the code provided by MotionKit::Events you'll be happy to see
|
71
|
+
that it is a *tiny* little gem. But using it to decouple your UI from your
|
72
|
+
controller can provide a huge long term benefit in terms of keeping your code
|
73
|
+
maintainable!
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
class LoginLayout < MK::Layout
|
77
|
+
|
78
|
+
def layout
|
79
|
+
add UITextField, :username_field do
|
80
|
+
delegate self
|
81
|
+
end
|
82
|
+
|
83
|
+
add UITextField, :password_field do
|
84
|
+
delegate self
|
85
|
+
end
|
86
|
+
|
87
|
+
add UIButton, :login_button do
|
88
|
+
on :touch do
|
89
|
+
trigger_login
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def trigger_login
|
95
|
+
# send the username and password to our controller
|
96
|
+
trigger :login, get(:username_field).text.to_s, get(:password_field).text.to_s
|
97
|
+
end
|
98
|
+
|
99
|
+
def textFieldShouldReturn(field)
|
100
|
+
if field == get(:password_field)
|
101
|
+
trigger_login
|
102
|
+
else
|
103
|
+
get(:password_field).becomeFirstResponder
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
```
|
109
|
+
|
110
|
+
The sample app (most of the code is in [app/ios/login/][login]) includes a working
|
111
|
+
version of this example.
|
112
|
+
|
113
|
+
[login]: https://github.com/rubymotion/motion-kit-events/tree/master/app/ios/login/
|
114
|
+
|
115
|
+
###### Note
|
116
|
+
|
117
|
+
The example and specs all require SugarCube to run; this is just because I
|
118
|
+
wanted to have the specs make sure that the `on` method (used in so many gems)
|
119
|
+
behaves the way you would expect it to.
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# @requires MotionKit::BaseLayout
|
2
|
+
module MotionKit
|
3
|
+
class BaseLayout
|
4
|
+
|
5
|
+
def motion_kit_event_handlers
|
6
|
+
@motion_kit_event_handlers ||= {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def on(*args, &handler)
|
10
|
+
if @context || @assign_root
|
11
|
+
apply_with_target(:on, *args, &handler)
|
12
|
+
else
|
13
|
+
event = args.first
|
14
|
+
unless event
|
15
|
+
raise ArgumentError.new('`event` is a required argument to Layout#on')
|
16
|
+
end
|
17
|
+
motion_kit_event_handlers[event] ||= []
|
18
|
+
motion_kit_event_handlers[event] << handler.weak!
|
19
|
+
|
20
|
+
self
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def trigger(*args, &handler)
|
25
|
+
if @context
|
26
|
+
apply(:trigger, *args, &handler)
|
27
|
+
else
|
28
|
+
event = args.first
|
29
|
+
unless event
|
30
|
+
raise ArgumentError.new('`event` is a required argument to Layout#on')
|
31
|
+
end
|
32
|
+
|
33
|
+
if motion_kit_event_handlers[event]
|
34
|
+
motion_kit_event_handlers[event].each do |handler|
|
35
|
+
handler.call(args[1..-1])
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
self
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
unless defined?(Motion::Project::Config)
|
2
|
+
raise "The MotionKit::Events gem must be required within a RubyMotion project Rakefile."
|
3
|
+
end
|
4
|
+
|
5
|
+
|
6
|
+
require 'motion-kit'
|
7
|
+
require 'dbt'
|
8
|
+
|
9
|
+
|
10
|
+
Motion::Project::App.setup do |app|
|
11
|
+
lib = File.join(File.dirname(__FILE__), 'motion-kit-events')
|
12
|
+
|
13
|
+
# scans app.files until it finds app/ (the default)
|
14
|
+
# if found, it inserts just before those files, otherwise it will insert to
|
15
|
+
# the end of the list
|
16
|
+
insert_point = app.files.find_index { |file| file =~ /^(?:\.\/)?app\// } || 0
|
17
|
+
|
18
|
+
Dir.glob(File.join(lib, '**/*.rb')).reverse.each do |file|
|
19
|
+
app.files.insert(insert_point, file)
|
20
|
+
end
|
21
|
+
|
22
|
+
DBT.analyze(app)
|
23
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
describe 'MotionKit::Events' do
|
2
|
+
tests EventsController
|
3
|
+
|
4
|
+
it 'should respond to the layout trigger' do
|
5
|
+
controller.success.should.not == true
|
6
|
+
controller.layout.trigger(:test)
|
7
|
+
controller.success.should == true
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should respond to the test button' do
|
11
|
+
controller.success.should.not == true
|
12
|
+
controller.test_button.trigger(:touch)
|
13
|
+
controller.success.should == true
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
metadata
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: motion-kit-events
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Colin T.A. Gray
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-05-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: motion-kit
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: dbt
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: |
|
42
|
+
Use +on+ and +trigger+ to send generic events from the layout to the controller.
|
43
|
+
email:
|
44
|
+
- colinta@gmail.com
|
45
|
+
executables: []
|
46
|
+
extensions: []
|
47
|
+
extra_rdoc_files: []
|
48
|
+
files:
|
49
|
+
- lib/motion-kit-events/layout.rb
|
50
|
+
- lib/motion-kit-events/version.rb
|
51
|
+
- lib/motion-kit-events.rb
|
52
|
+
- README.md
|
53
|
+
- spec/ios/events_spec.rb
|
54
|
+
homepage: https://github.com/rubymotion/motion-kit-events
|
55
|
+
licenses:
|
56
|
+
- BSD
|
57
|
+
metadata: {}
|
58
|
+
post_install_message:
|
59
|
+
rdoc_options: []
|
60
|
+
require_paths:
|
61
|
+
- lib
|
62
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - '>='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - '>='
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
requirements: []
|
73
|
+
rubyforge_project:
|
74
|
+
rubygems_version: 2.0.3
|
75
|
+
signing_key:
|
76
|
+
specification_version: 4
|
77
|
+
summary: Adds simple event methods to MotionKit::Layout classes.
|
78
|
+
test_files:
|
79
|
+
- spec/ios/events_spec.rb
|