Skip to content
Newer
Older
100644 187 lines (139 sloc) 6.22 KB
6d308af @MGPalmer Renaming schemer to masterplan - "schemer" is already a gem on rubyge…
MGPalmer authored
1 = Masterplan
29a1dea @MGPalmer Initial commit to schemer.
MGPalmer authored
2
6d308af @MGPalmer Renaming schemer to masterplan - "schemer" is already a gem on rubyge…
MGPalmer authored
3 Masterplan is a library for comparing Ruby data structures against predefined templates.
026d6d5 @MGPalmer Basic readme and filling out the blanks for the gemspec
MGPalmer authored
4
40cd466 @MGPalmer Adding more documentation.
MGPalmer authored
5 At Travel IQ, this is used to define a canonical definition of the structure and format of the requests and responses of our APIs.
6 In short, you get something that is similar to a XML Scheme - a template against which your data can be compared, to
7 ensure its correctness programmatically. Only without the XML part.
8
9 Examples make this easier to explain. Say you have a webservice or class that produces
10 a Ruby data structure like this:
11
3371be2 @MGPalmer * Realized that a Document can only be created from a Hash right now
MGPalmer authored
12 {
13 :airports => [
14 {
15 :name => "Tegel Airport",
16 :code => "TXL",
17 :latitude => 2.35454,
18 :longitude => 54.67867
19 },
20 {
21 :name => "Schönefeld Airport",
22 :code => "SXF",
23 :latitude => 5.35454,
24 :longitude => 34.67867
25 }
26 ]
27 }
40cd466 @MGPalmer Adding more documentation.
MGPalmer authored
28
29 and so on and so forth. In your tests of this service, you want to make sure that this
30 structure follows certain rules:
31
3371be2 @MGPalmer * Realized that a Document can only be created from a Hash right now
MGPalmer authored
32 * It's a Hash with one key, :airports
33 * The value is an Array, and it can be empty, but not null
40cd466 @MGPalmer Adding more documentation.
MGPalmer authored
34 * Each entry is a hash
35 * Each hash has the keys :name, :code, :latitude, :longitude
36 * No value of these keys is ever null
37 * Name and code are strings
38 * The strings aren't empty
39 * The code is three characters long and consists of uppercase letters
40 * Latitude and Longitude are floats
41
42 In a more XML-centric world, you would define an XML (or Relax-NG etc.) Scheme that defines all
43 these rules and then use that to validate your output. But we also want to deliver JSON...so we'll define
6d308af @MGPalmer Renaming schemer to masterplan - "schemer" is already a gem on rubyge…
MGPalmer authored
44 the rules as a Masterplan::Document, and validate the data while it's still Ruby, and say that as long
40cd466 @MGPalmer Adding more documentation.
MGPalmer authored
45 as the source data is correct, the representation in JSON or XML will also be correct:
46
6d308af @MGPalmer Renaming schemer to masterplan - "schemer" is already a gem on rubyge…
MGPalmer authored
47 include Masterplan::DefineRules
40cd466 @MGPalmer Adding more documentation.
MGPalmer authored
48
6d308af @MGPalmer Renaming schemer to masterplan - "schemer" is already a gem on rubyge…
MGPalmer authored
49 doc = Masterplan::Document.new(
3371be2 @MGPalmer * Realized that a Document can only be created from a Hash right now
MGPalmer authored
50 :airports => [
40cd466 @MGPalmer Adding more documentation.
MGPalmer authored
51 {
52 :name => "Tegel Airport",
53 :code => rule("TXL", :matches => /[A-Z]{3}/),
54 :latitude => 2.35454,
55 :longitude => 54.67867
56 },
57 {
58 :name => "Schönefeld Airport",
59 :code => "SXF",
60 :latitude => 5.35454,
61 :longitude => 34.67867
62 }
63 ]
64 )
65
66 It doesn't look much different from the example, but there are a lot of rules built-in.
67 You can now use the doc object to check your data against the template:
68
6d308af @MGPalmer Renaming schemer to masterplan - "schemer" is already a gem on rubyge…
MGPalmer authored
69 Masterplan.compare(:scheme => doc, :to => [{:example => :data}])
40cd466 @MGPalmer Adding more documentation.
MGPalmer authored
70
6d308af @MGPalmer Renaming schemer to masterplan - "schemer" is already a gem on rubyge…
MGPalmer authored
71 And it will throw a Masterplan::FailedError exception, and print out debugging data:
3371be2 @MGPalmer * Realized that a Document can only be created from a Hash right now
MGPalmer authored
72
6d308af @MGPalmer Renaming schemer to masterplan - "schemer" is already a gem on rubyge…
MGPalmer authored
73 >> Masterplan.compare(:scheme => doc, :to => {:example => :data})
74 Masterplan::FailedError: keys don't match in 'root':
3371be2 @MGPalmer * Realized that a Document can only be created from a Hash right now
MGPalmer authored
75 expected: airports
76 received: example
77
78 Expected:
79 {"airports"=>
80 [{:latitude=>2.35454,
81 :longitude=>54.67867,
82 :code=>
6d308af @MGPalmer Renaming schemer to masterplan - "schemer" is already a gem on rubyge…
MGPalmer authored
83 #<Masterplan::Rule:0x6d0bd70
3371be2 @MGPalmer * Realized that a Document can only be created from a Hash right now
MGPalmer authored
84 @example_value="TXL",
85 @options=
86 {"compare_each"=>false,
87 "allow_nil"=>false,
88 "included_in"=>false,
89 "matches"=>/[A-Z]{3}/}>,
90 :name=>"Tegel Airport"},
91 {:latitude=>5.35454,
92 :longitude=>34.67867,
93 :code=>"SXF",
94 :name=>"Schönefeld Airport"}]}
95
96
97 but was:
98 {"example"=>:data}
99
100 Another example:
101
6d308af @MGPalmer Renaming schemer to masterplan - "schemer" is already a gem on rubyge…
MGPalmer authored
102 >> Masterplan.compare(:scheme => doc, :to => {:airports => [{:name => "Bla", :latitude => 1.1, :longitude => 2.3, :code => "XXx"}]})
103 Masterplan::FailedError: value at 'root'=>'airports'=>'0'=>'code' "XXx" (String) does not match /[A-Z]{3}/ !
3371be2 @MGPalmer * Realized that a Document can only be created from a Hash right now
MGPalmer authored
104
105 Expected:
106 {"name"=>"Tegel Airport",
107 "latitude"=>2.35454,
108 "code"=>
6d308af @MGPalmer Renaming schemer to masterplan - "schemer" is already a gem on rubyge…
MGPalmer authored
109 #<Masterplan::Rule:0x6d0bd70
3371be2 @MGPalmer * Realized that a Document can only be created from a Hash right now
MGPalmer authored
110 @example_value="TXL",
111 @options=
112 {"compare_each"=>false,
113 "allow_nil"=>false,
114 "included_in"=>false,
115 "matches"=>/[A-Z]{3}/}>,
116 "longitude"=>54.67867}
117
118
119 but was:
120 {"name"=>"Bla", "latitude"=>1.1, "code"=>"XXx", "longitude"=>2.3}
40cd466 @MGPalmer Adding more documentation.
MGPalmer authored
121
122 The implicit rules are:
123
124 * Each object in the data needs to be of the same class as in the template
125 * hash keys must match up
126 * The first element of an Array in the template is used as the template for all elements in the data. That's why we didn't
127 have to restate the custom rule about the code in the above example, as only the "Tegel Airport" hash is used for all checks.
128
6d308af @MGPalmer Renaming schemer to masterplan - "schemer" is already a gem on rubyge…
MGPalmer authored
129 You can add extra rules with the rule method - see Masterplan::DefineRules#rule for details.
40cd466 @MGPalmer Adding more documentation.
MGPalmer authored
130
131 There is also an added assertion for unit tests or specs:
132
6d308af @MGPalmer Renaming schemer to masterplan - "schemer" is already a gem on rubyge…
MGPalmer authored
133 assert_masterplan(doc, [{:example => :data})
40cd466 @MGPalmer Adding more documentation.
MGPalmer authored
134
42fa892 @MGPalmer Updating docs and gemspec
MGPalmer authored
135 == Use schemes as examples in documentation
136
40cd466 @MGPalmer Adding more documentation.
MGPalmer authored
137 A problem with webservices is that you need to keep the documentation up to date - something
6d308af @MGPalmer Renaming schemer to masterplan - "schemer" is already a gem on rubyge…
MGPalmer authored
138 that is easily forgotten. If you have a masterplan document, you can use it not only as the template,
40cd466 @MGPalmer Adding more documentation.
MGPalmer authored
139 but also as an example in, say, online documentation:
140
141 <pre>
142 <%= JSON.dump(doc.to_hash) %>
143 </pre>
144
6d308af @MGPalmer Renaming schemer to masterplan - "schemer" is already a gem on rubyge…
MGPalmer authored
145 The to_hash method removes the Masterplan::Rule objects for clean output.
40cd466 @MGPalmer Adding more documentation.
MGPalmer authored
146
42fa892 @MGPalmer Updating docs and gemspec
MGPalmer authored
147 == Caveat
148
149 Note that for the moment, schemes, i.e. the outermost object, can only be hashes.
150
026d6d5 @MGPalmer Basic readme and filling out the blanks for the gemspec
MGPalmer authored
151 == Installation
152
7818046 @MGPalmer Now as it's released on gemcutter, add that to docs.
MGPalmer authored
153 (sudo) gem install masterplan
026d6d5 @MGPalmer Basic readme and filling out the blanks for the gemspec
MGPalmer authored
154
7818046 @MGPalmer Now as it's released on gemcutter, add that to docs.
MGPalmer authored
155 Or, install latest version from Github with bundler by adding this to your Gemfile:
026d6d5 @MGPalmer Basic readme and filling out the blanks for the gemspec
MGPalmer authored
156
7818046 @MGPalmer Now as it's released on gemcutter, add that to docs.
MGPalmer authored
157 gem 'masterplan', :git => 'git://github.com/traveliq/masterplan.git'
026d6d5 @MGPalmer Basic readme and filling out the blanks for the gemspec
MGPalmer authored
158
1fa8cc3 @MGPalmer Wretched compatability with Ruby 1.9...
MGPalmer authored
159 == Dependencies
160
161 You'll need ActiveSupport, but that should be handled automatically.
162 Under Ruby 1.9.x, however, you need the test-unit gem. It works for us with test-unit 1.2.3.
163
026d6d5 @MGPalmer Basic readme and filling out the blanks for the gemspec
MGPalmer authored
164 == Authors
165
c7237e1 @MGPalmer Fame and glory !
MGPalmer authored
166 Martin Tepper (monogreen.de), Holger Pillmann (holger.pillmann@gmail.com), Dr. Florian Odronitz (odo@mac.com)
026d6d5 @MGPalmer Basic readme and filling out the blanks for the gemspec
MGPalmer authored
167
168 == Contact
169
170 For questions, contact the authors or developer@traveliq.net
29a1dea @MGPalmer Initial commit to schemer.
MGPalmer authored
171
6d308af @MGPalmer Renaming schemer to masterplan - "schemer" is already a gem on rubyge…
MGPalmer authored
172 == Contributing to masterplan
026d6d5 @MGPalmer Basic readme and filling out the blanks for the gemspec
MGPalmer authored
173
29a1dea @MGPalmer Initial commit to schemer.
MGPalmer authored
174 * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
175 * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
176 * Fork the project
177 * Start a feature/bugfix branch
178 * Commit and push until you are happy with your contribution
179 * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
180 * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
181
182 == Copyright
183
026d6d5 @MGPalmer Basic readme and filling out the blanks for the gemspec
MGPalmer authored
184 Copyright (c) 2011 www.travel-iq.com. See LICENSE.txt for
29a1dea @MGPalmer Initial commit to schemer.
MGPalmer authored
185 further details.
186
Something went wrong with that request. Please try again.