czar 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 471ebb54150c95923d569f6ce7d32072a17974e8
4
- data.tar.gz: 4cf441e9b83e54c5cd5f558fa03018481f6f67a5
3
+ metadata.gz: 7ff3361aa69a60086e6d183164eb351347aa671b
4
+ data.tar.gz: 7e39e13e6b3d1db2961f1534dd7cf472aeacd779
5
5
  SHA512:
6
- metadata.gz: 0362a5ee711c89fa76765e2585ada348990f7d9fa8ce30c5d478e20a4693153c8867d7cf72e0ee4df807ac686bc68feb6c213fcb1b3ba2d2a9d34439829c7893
7
- data.tar.gz: fc23abaa9a1d2af589d2ab0515b43fd8a403b3cfb510ab9c00839752385ee38fd6d7187fb34793792b41123613e77613ff55514da08a1b6408964beddeca9416
6
+ metadata.gz: 9daac98d456d7015df0b4d73976a2fdd7be67126384ea0346a724ff18de9ec55d5988aaedc6634437c14b1cb69dc6dfbf1275dcb67f0986063b07d075af0eeed
7
+ data.tar.gz: bc90d90e5daad1b22bae48c6000dbf256546d808172da009616fda721de9b3a9d6f744d02222922af357a91a3ba27061ba224c37387eee54e45961fbec4eff47
data/README.md CHANGED
@@ -1,23 +1,45 @@
1
1
  # Czar
2
2
 
3
3
  Czar is a framework for building applications around the Command
4
- pattern.
4
+ pattern. However, it is intended that these commands will stop at
5
+ various points during their lifetime, then resume again a bit later.
6
+ Maybe in response to incoming web-requests, because there's a
7
+ background timer in action, or simply because we are waiting on an
8
+ external resource.
5
9
 
6
10
  Everything your application does is a Command of some kind; those
7
11
  commands may be simple actions, sequences of actions, sequences with
8
- decisions within them or series that trigger other commands.
9
-
10
- The advantage of using commands within, for example, a Rails application
11
- is that you can then make your database model classes *passive* - that
12
- is they become purely data - and the interesting stuff is all handled by
13
- commands. No more fat models with callbacks all over the place.
14
-
15
- Plus using commands makes it easy to ensure that authorisation is done
16
- correctly (as each command is well-defined) and makes it trivial to add
17
- in logging and so on.
12
+ decisions within them or series that trigger other commands. Czar is
13
+ intended to make those commands explicit - when your user reads some
14
+ data, makes a change to something or updates an item, each one of those
15
+ is a command flowing through your system. Representing them as their
16
+ own individual objects simplifies authorisation and can mean your code
17
+ is much simpler. For example, in a Rails app, you would often rely on
18
+ callbacks to trigger various actions on a given model. But if you use a
19
+ UpdatesGivenModel command, you can write some linear code to handle all
20
+ updates, logging, after_update handlers, instead of piecing together a
21
+ trail of callbacks. And as you can build complex commands by
22
+ aggregating multiple child commands, it also makes testing your app
23
+ simpler, as well as making its processes more explicit.
18
24
 
19
25
  Czar can allow commands to be persisted (with a in-memory and a Redis adapter for now).
20
26
 
27
+ The original requirement for Czar was in an application that did an
28
+ import of products from a CSV. As this could be a very long-running
29
+ task, each operation was put onto a background queue and the system was
30
+ scaled by adding new worker processes. Each product, as it was being imported,
31
+ may have required several images to be imported from an FTP server; so
32
+ there were many tasks that could all happen in parallel: reading the
33
+ CSV, updating or adding individual products, searching for and importing
34
+ images from the FTP server, attaching imported images to products.
35
+
36
+ So the ImportsCsv command would spawn several hundred ImportsProduct commands,
37
+ and dependent upon the data, each of those could spawn several
38
+ ImportsImageFromFtpServer and AttachesImageToProducts tasks. But all the
39
+ user cares about is "when will the import be done?". So the parent ImportsCsv command keeps track
40
+ of its child tasks and, being persistent, can report its progress back
41
+ to the web application.
42
+
21
43
  ## Installation
22
44
 
23
45
  Add this line to your application's Gemfile:
@@ -36,6 +58,7 @@ Or install it yourself as:
36
58
 
37
59
  The Command module represents an implementation of the Command pattern
38
60
  where each Command has an internal state machine and can optionally spawn child commands.
61
+
39
62
  At its simplest, a Command will be executed, moving it from "start" state to "complete" state.
40
63
  For example:
41
64
  ```
@@ -53,12 +76,12 @@ class SimpleCommand
53
76
  end
54
77
  ```
55
78
 
56
- To use this, simply call SimpleCommand.new.execute - the command will perform #some_complex_calculation and then be marked as :complete
79
+ To use this, simply call SimpleCommand.new.execute - the command will perform #some_complex_calculation and then be marked as :complete - we can then find out what happend by calling the #result method.
57
80
 
58
81
  By itself, this is pretty boring. However, as we've got a simple state machine in there, we can do more interesting stuff; especially when a command is persistent.
59
82
 
60
83
  For example:
61
-
84
+ ```
62
85
  class DrivesACar
63
86
  include Czar::Command
64
87
 
@@ -71,7 +94,7 @@ class DrivesACar
71
94
  if has_reached_destination?
72
95
  mark_as :complete
73
96
  elsif traffic_light.colour == :green
74
- mark_as :driving
97
+ mark_as :moving
75
98
  else
76
99
  mark_as :stopped
77
100
  end
@@ -85,6 +108,7 @@ class DrivesACar
85
108
  # code goes here
86
109
  end
87
110
  end
111
+ ```
88
112
 
89
113
  In this case, we instantiate a DrivesACar command and store it somewhere. Every now and then (in response to a timer, a cron job or some other trigger) we call execute, which looks at the command's internal state and chooses if it is moving or stopped. Eventually, when we have reached our destination, the command is marked as complete. Also note, that as we do nothing when stopped, there's no need to define a stopped method.
90
114
 
@@ -92,6 +116,7 @@ Commands can also trigger child commands, and are notified when the child comple
92
116
 
93
117
  For example:
94
118
 
119
+ ```
95
120
  class CourierDeliversAParcel < Struct.new(:pickup_location, :dropoff_location)
96
121
  include Czar::Command
97
122
 
@@ -109,6 +134,7 @@ class CourierDeliversAParcel < Struct.new(:pickup_location, :dropoff_location)
109
134
  end
110
135
  end
111
136
  end
137
+ ```
112
138
 
113
139
  ## Contributing
114
140
 
data/lib/czar/command.rb CHANGED
@@ -33,7 +33,7 @@ module Czar
33
33
 
34
34
  def mark_as state, params = {}
35
35
  @state = state.to_sym
36
- @internal_state = params.dup
36
+ @internal_state = internal.merge(params)
37
37
  notify_parent if @state == :complete
38
38
  end
39
39
 
data/lib/czar/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Czar
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -101,6 +101,41 @@ describe Czar::Command do
101
101
  end
102
102
  end
103
103
 
104
+ describe "updating internal state" do
105
+ subject { internal_state_task.new }
106
+
107
+ it "ensures any internal state is maintained" do
108
+ subject.execute
109
+ subject.this.must_equal true
110
+ subject.execute
111
+ subject.that.must_equal true
112
+ subject.this.must_equal true
113
+ end
114
+
115
+ let(:internal_state_task) do
116
+ Class.new do
117
+ include Czar::Command
118
+
119
+ def start
120
+ mark_as :doing_stuff, this: true
121
+ end
122
+
123
+ def doing_stuff
124
+ mark_as :done_stuff, that: true
125
+ end
126
+
127
+ def this
128
+ internal[:this]
129
+ end
130
+
131
+ def that
132
+ internal[:that]
133
+ end
134
+ end
135
+
136
+ end
137
+ end
138
+
104
139
  describe "triggering child commands" do
105
140
  subject { parent_task.new }
106
141
 
@@ -126,10 +161,6 @@ describe Czar::Command do
126
161
  mark_as :waiting_for_child_to_complete
127
162
  end
128
163
 
129
- def waiting_for_child_to_complete
130
- sleep 0.1
131
- end
132
-
133
164
  def child_task_completed child_task
134
165
  mark_as :complete
135
166
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: czar
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rahoul Baruah
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-16 00:00:00.000000000 Z
11
+ date: 2014-07-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler