cucumber-in-the-yard 1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. data/History.txt +3 -0
  2. data/Manifest +51 -0
  3. data/README.txt +55 -0
  4. data/Rakefile +28 -0
  5. data/cucumber-in-the-yard.gemspec +42 -0
  6. data/example/example.feature +13 -0
  7. data/example/example.step.rb +48 -0
  8. data/example/example.third.feature +30 -0
  9. data/example/second_example.feature +36 -0
  10. data/lib/city.rb +23 -0
  11. data/lib/cucumber/city_builder.rb +130 -0
  12. data/lib/yard/code_objects/cucumber_location_helper.rb +15 -0
  13. data/lib/yard/code_objects/feature.rb +24 -0
  14. data/lib/yard/code_objects/scenario.rb +25 -0
  15. data/lib/yard/code_objects/step.rb +25 -0
  16. data/lib/yard/code_objects/tags.rb +63 -0
  17. data/lib/yard/extensions.rb +38 -0
  18. data/lib/yard/handlers/base.rb +21 -0
  19. data/lib/yard/handlers/feature_handler.rb +41 -0
  20. data/lib/yard/parser/feature.rb +46 -0
  21. data/lib/yard/rake/city_task.rb +12 -0
  22. data/lib/yard/rb_extensions.rb +152 -0
  23. data/lib/yard/templates/default/feature/html/feature.erb +243 -0
  24. data/lib/yard/templates/default/feature/setup.rb +5 -0
  25. data/lib/yard/templates/default/fulldoc/html/css/common.css +182 -0
  26. data/lib/yard/templates/default/fulldoc/html/full_list.erb +34 -0
  27. data/lib/yard/templates/default/fulldoc/html/full_list_features.erb +10 -0
  28. data/lib/yard/templates/default/fulldoc/html/full_list_scenarios.erb +10 -0
  29. data/lib/yard/templates/default/fulldoc/html/full_list_stepdefinitions.erb +11 -0
  30. data/lib/yard/templates/default/fulldoc/html/full_list_steps.erb +13 -0
  31. data/lib/yard/templates/default/fulldoc/html/full_list_tagusages.erb +10 -0
  32. data/lib/yard/templates/default/fulldoc/html/index.erb +24 -0
  33. data/lib/yard/templates/default/fulldoc/html/js/cucumber.js +13 -0
  34. data/lib/yard/templates/default/fulldoc/html/setup.rb +73 -0
  35. data/lib/yard/templates/default/layout/html/headers.erb +14 -0
  36. data/lib/yard/templates/default/layout/html/search.erb +8 -0
  37. data/lib/yard/templates/default/module/html/step_transforms.erb +23 -0
  38. data/lib/yard/templates/default/module/setup.rb +5 -0
  39. data/lib/yard/templates/default/scenario/html/scenario.erb +26 -0
  40. data/lib/yard/templates/default/scenario/setup.rb +5 -0
  41. data/lib/yard/templates/default/steptransformers/html/stepdefinition.erb +38 -0
  42. data/lib/yard/templates/default/steptransformers/setup.rb +5 -0
  43. data/lib/yard/templates/default/tagusage/html/tagusage.erb +65 -0
  44. data/lib/yard/templates/default/tagusage/setup.rb +5 -0
  45. data/spec/city/feature_parser_spec_examples.rb +153 -0
  46. data/spec/city/gherkin_loader_spec.rb +39 -0
  47. data/spec/city/test.feature +36 -0
  48. data/spec/city/yard_handlers_cucumber_spec.rb +24 -0
  49. data/spec/city/yard_namespace_object_spec.rb +8 -0
  50. data/spec/city/yard_parser_cucumber_spec.rb +215 -0
  51. data/spec/city/yard_rb_extensions_spec.rb +128 -0
  52. data/spec/spec_helper.rb +5 -0
  53. data.tar.gz.sig +0 -0
  54. metadata +201 -0
  55. metadata.gz.sig +0 -0
@@ -0,0 +1,153 @@
1
+
2
+ shared_examples_for "a feature file" do
3
+ it "should have a defined feature" do
4
+ @parser.features.first.should_not be_nil
5
+ end
6
+
7
+ it "the feature should have a unique name" do
8
+ @parser.features.first.name.should == @feature[:file].gsub('.','_').to_sym
9
+ end
10
+
11
+ it "the feature should have the specified title" do
12
+ @parser.features.first.value.should == @feature[:name]
13
+ end
14
+
15
+ it "the feature should have all specified tags" do
16
+ @feature[:tags].find do |expected_tag|
17
+ @parser.features.first.tags.find{|tag| tag.value == expected_tag }
18
+ end.should_not be_nil
19
+ end
20
+
21
+ it "the feature should have the correct number of tags" do
22
+ @feature[:tags].each do |expected_tag|
23
+ @parser.features.first.tags.find_all {|tag| tag.value == expected_tag }.count.should == 1
24
+ end
25
+ end
26
+
27
+ it "the feature's tags should have a file" do
28
+ @parser.features.first.tags.each do |tag|
29
+ tag.files.should_not be_nil
30
+ tag.files.should_not be_empty
31
+ tag.files.first.first.should == @feature[:file]
32
+ end
33
+ end
34
+
35
+ it "the feature should have a description" do
36
+ @parser.features.first.description.join("\n") == @feature[:description].join("\n")
37
+ end
38
+
39
+ it "the feature should have a file" do
40
+ @parser.features.first.files.first[0].should == @feature[:file]
41
+ end
42
+
43
+ it "the feature should have a line number" do
44
+ @parser.features.first.files.first[1].should_not be_nil
45
+ end
46
+
47
+ end
48
+
49
+ shared_examples_for "a feature file with a background" do
50
+
51
+ it "the feature should have a background" do
52
+ @parser.features.first.background.should_not be_nil
53
+ end
54
+
55
+ it "the background should have a unique scenario name" do
56
+ @parser.features.first.background.name.should == "#{@feature[:file]}.background".gsub('.','_').to_sym
57
+ end
58
+
59
+ it "the background should have the correct title" do
60
+ @parser.features.first.background.value.should == "Background"
61
+ end
62
+
63
+ it "the background should have a file" do
64
+ @parser.features.first.background.files.first[0].should == @feature[:file]
65
+ end
66
+
67
+ it "the background should have a line number" do
68
+ @parser.features.first.background.files.first[1].should_not be_nil
69
+ end
70
+
71
+ it "the background should have all their defined steps" do
72
+ @parser.features.first.scenarios.first.steps.should_not be_nil
73
+ if @background
74
+ @background.each_with_index do |step,index|
75
+ @parser.features.first.background.steps[index].value.should == step
76
+ end
77
+ end
78
+ end
79
+
80
+ it "the background steps should have files and line numbers" do
81
+ if @background
82
+ @background.each_with_index do |step,index|
83
+ @parser.features.first.background.steps[index].files.first[0].should == @feature[:file]
84
+ @parser.features.first.background.steps[index].files.first[1].should_not be_nil
85
+ end
86
+ end
87
+ end
88
+
89
+ end
90
+
91
+ shared_examples_for "a feature file with scenarios" do
92
+ it "should have all scenarios" do
93
+ @scenarios.each_with_index do |scenario,index|
94
+ @parser.features.first.scenarios[index].should_not be_nil
95
+ end
96
+ end
97
+
98
+ it "each scenario should have a unique scenario name" do
99
+ @parser.features.first.scenarios.first.name.should == "#{@feature[:file]}_scenario_0".gsub('.','_').to_sym
100
+ end
101
+
102
+ it "each scenario should have the correct title" do
103
+ @parser.features.first.scenarios.each_with_index do |scenario,index|
104
+ scenario.value.should == @scenarios[index][:title].join("\n")
105
+ end
106
+ end
107
+
108
+ it "each scenario should have the correct tags" do
109
+ @scenarios.each_with_index do |scenario,index|
110
+ scenario[:tags].each do |expeced_tag|
111
+ @parser.features.first.scenarios[index].tags.find {|tag| tag.value == expeced_tag}.should_not be_nil
112
+ end
113
+ end
114
+ end
115
+
116
+ it "each scenario should have the correct number of tags" do
117
+ @parser.features.first.scenarios.first.tags.find_all {|tag| tag.value == "@ninja" }.count.should == 1
118
+ end
119
+
120
+ it "each scenario should have a file" do
121
+ @parser.features.first.scenarios.first.files.first[0].should == @feature[:file]
122
+ end
123
+
124
+ it "each scenario should have a line number" do
125
+ @parser.features.first.scenarios.first.files.first[1].should_not be_nil
126
+ end
127
+
128
+ it "each scenario should have all their defined steps" do
129
+ @parser.features.first.scenarios.first.steps.should_not be_nil
130
+ if @scenarios
131
+ @scenarios.each_with_index do |scenario,scenario_index|
132
+ @parser.features.first.scenarios[scenario_index].should_not be_nil
133
+
134
+ scenario[:steps].each_with_index do |step,step_index|
135
+ @parser.features.first.scenarios[scenario_index].steps[step_index].name.should == "#{@feature[:file].gsub('.','_')}_scenario_#{scenario_index}_step_#{step_index}".to_sym
136
+ @parser.features.first.scenarios[scenario_index].steps[step_index].value.should == step
137
+ end
138
+ end
139
+ end
140
+ end
141
+
142
+ it "each scenario's steps should have files and line numbers" do
143
+ if @scenarios
144
+ @scenarios.each_with_index do |scenario,scenario_index|
145
+ scenario[:steps].each_with_index do |step,step_index|
146
+ @parser.features.first.scenarios[scenario_index].steps[step_index].files.first[0].should == @feature[:file]
147
+ @parser.features.first.scenarios[scenario_index].steps[step_index].files.first[1].should_not be_nil
148
+ end
149
+ end
150
+ end
151
+ end
152
+
153
+ end
@@ -0,0 +1,39 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "Gherkin" do
4
+
5
+
6
+ before(:all) do
7
+
8
+ @source = File.dirname(__FILE__) + '/test.feature'
9
+ File.should exist(@source)
10
+ @data = File.open(@source, 'r').read
11
+
12
+ @parser = YARD::Parser::Cucumber::FeatureParser.new(@data,@source)
13
+
14
+ end
15
+
16
+
17
+ it "should not be nil" do
18
+ @parser.should_not be_nil
19
+ end
20
+
21
+ it "should parse" do
22
+ @parser.parse
23
+ end
24
+
25
+ it "should tokenize" do
26
+ @parser.tokenize
27
+ end
28
+
29
+ it "should enumerator" do
30
+ @parser.enumerator
31
+ end
32
+
33
+
34
+
35
+
36
+
37
+
38
+
39
+ end
@@ -0,0 +1,36 @@
1
+ @customer
2
+ Feature: Customer Logout Feature
3
+ As a customer of the product I am able to logout
4
+
5
+ Background:
6
+ Given this undefined step definition
7
+
8
+ @bvt
9
+ Scenario: Customer that is logged in is able to log out
10
+ Given that a customer is a valid customer
11
+ And a customer logs in as username 'frank' with password 'default'
12
+ And I expect them to have logged in successfully
13
+ When the customer logs out
14
+ Then I expect the customer to be shown the logout page
15
+
16
+ Scenario: Customers with a complete profile are allowed to post
17
+ Given that a customer is a valid customer
18
+ And the customer has the following details:
19
+ | Name | Email | Age |
20
+ | Frank | f@email.com | 22 |
21
+ When a customer logs in as username 'frank' with password 'default'
22
+ And visits the customer update page
23
+ Then I expect the customer is able able to post to their profile
24
+
25
+ @product
26
+ Scenario Outline: Customers that bought a product are included in their product groups
27
+ Given that <Customer> is a valid customer
28
+ And that the product, named '<Product>', is a valid product
29
+ When the customer has purchased the product
30
+ Then I expect the customer to be a member of the '<Product>' group
31
+
32
+ Examples:
33
+ | Customer | Product |
34
+ | Customer A | Product A |
35
+ | Customer A | Product B |
36
+ | Customer A | Product C |
@@ -0,0 +1,24 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ module YARD::Handlers::Cucumber
4
+
5
+ describe Base do
6
+
7
+ it "should respond to method handles?" do
8
+ Base.should respond_to(:handles?)
9
+ end
10
+
11
+ end
12
+
13
+ describe FeatureHandler do
14
+
15
+ it "should respond to method process" do
16
+ FeatureHandler.should respond_to(:process)
17
+ end
18
+
19
+ end
20
+
21
+
22
+
23
+
24
+ end
@@ -0,0 +1,8 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ module YARD::CodeObjects
4
+
5
+ describe NamespaceObject do
6
+ end
7
+
8
+ end
@@ -0,0 +1,215 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require File.dirname(__FILE__) + '/feature_parser_spec_examples.rb'
3
+
4
+ module YARD::Parser::Cucumber
5
+
6
+ describe YARD::CodeObjects::Cucumber::Tag do
7
+
8
+ [:value].each do |attribute|
9
+ it "should respond to method #{attribute}" do
10
+ YARD::CodeObjects::Cucumber::Tag.new(:root,"tag_name").should respond_to(attribute)
11
+ end
12
+ end
13
+
14
+ end
15
+
16
+ describe YARD::CodeObjects::Cucumber::Step do
17
+
18
+ [:value, :definition].each do |attribute|
19
+ it "should respond to method #{attribute}" do
20
+ YARD::CodeObjects::Cucumber::Step.new(:root,"name").should respond_to(attribute)
21
+ end
22
+ end
23
+
24
+ it "should return the line prefix and the remainder" do
25
+ step = YARD::CodeObjects::Cucumber::Step.new(:root,"name") {|s| s.value = "Given something something" }
26
+ step.keyword.should == "Given"
27
+ step.line.should == "something something"
28
+ end
29
+
30
+ end
31
+
32
+ describe YARD::CodeObjects::Cucumber::Scenario do
33
+
34
+ [:value, :description, :steps, :tags ].each do |attribute|
35
+ it "should respond to method #{attribute}" do
36
+ YARD::CodeObjects::Cucumber::Scenario.new(:root,"name").should respond_to(attribute)
37
+ end
38
+ end
39
+
40
+ end
41
+
42
+ describe YARD::CodeObjects::Cucumber::Feature do
43
+
44
+ [:value, :description, :scenarios, :background, :tags ].each do |attribute|
45
+ it "should respond to method #{attribute}" do
46
+ YARD::CodeObjects::Cucumber::Feature.new(:root,"name").should respond_to(attribute)
47
+ end
48
+ end
49
+
50
+ end
51
+
52
+
53
+ describe FeatureParser do
54
+
55
+
56
+ it "should accept source and a file when created" do
57
+ lambda { FeatureParser.new("source code","filename") }.should_not raise_exception(Exception)
58
+ end
59
+
60
+ [ "parse", "tokenize", "enumerator" ].each do |required_method|
61
+ it "should have a method named #{required_method}" do
62
+ FeatureParser.instance_methods.should include(required_method)
63
+ end
64
+ end
65
+
66
+ it "should return itself when parse is called" do
67
+ parser = FeatureParser.new("source","filename")
68
+ parser.parse.should == parser
69
+ end
70
+
71
+ context "feature file with tags, feature, and description" do
72
+
73
+ before(:all) do
74
+ @feature = { :file => 'new.exciting.feature',
75
+ :name => "New Exciting Feature",
76
+ :tags => [ "@bvt", "@build", "@wip" ],
77
+ :description => [ "This feature is going to save the company." ] }
78
+
79
+ @parser = FeatureParser.new(%{
80
+ #{@feature[:tags].join(" ")}
81
+ Feature: #{@feature[:name]}
82
+ #{@feature[:description].join("\n")}
83
+ },@feature[:file])
84
+
85
+ @parser = @parser.parse
86
+ end
87
+
88
+ after(:all) do
89
+ @parser = nil
90
+ end
91
+
92
+ it_should_behave_like "a feature file"
93
+
94
+ end
95
+
96
+ context "feature file with a description that uses step keywords" do
97
+
98
+ before(:all) do
99
+ @feature = { :file => 'description.with.keywords.feature',
100
+ :name => "Fully Described Feature",
101
+ :tags => [ "@bvt", "@build", "@wip" ],
102
+ :description => ["As a product owner",
103
+ "When I ask about the work done",
104
+ "Then I want to see what this cukes things is all about",
105
+ "And I really want a straight answer",
106
+ "Given that I can be provided with one"] }
107
+
108
+ @parser = FeatureParser.new(%{
109
+ #{@feature[:tags].join(" ")}
110
+ Feature: #{@feature[:name]}
111
+ #{@feature[:description].join("\n")}
112
+ },@feature[:file])
113
+
114
+ @parser = @parser.parse
115
+ end
116
+
117
+ after(:all) do
118
+ @parser = nil
119
+ end
120
+
121
+ it_should_behave_like "a feature file"
122
+
123
+ end
124
+
125
+
126
+ context "feature file with background and one scenario" do
127
+
128
+ before(:all) do
129
+
130
+ @feature = { :file => "ninja.exciting.feature",
131
+ :name => "Ninja Feature Set",
132
+ :tags => [ "@bvt", "@build", "@wip" ],
133
+ :description => ["This feature is going to save the company"] }
134
+
135
+ @background = [ "Given that I have taken a nap" ]
136
+
137
+ @scenarios = [ { :tags => ["@ninja"],
138
+ :title => ["Ninja striking an opponent in the morning"],
139
+ :steps => [ "Given that there is an opponent",
140
+ "And a reason to fight him",
141
+ "When I karate strike him",
142
+ "Then I expect him to fall" ] } ]
143
+
144
+ @parser = FeatureParser.new(%{
145
+ #{@feature[:tags].join(" ")}
146
+ Feature: #{@feature[:name]}
147
+ #{@feature[:description].join("\n")}
148
+ Background:
149
+ #{@background.join("\n")}
150
+ #{@scenarios.first[:tags].join(" ")}
151
+ Scenario: #{@scenarios.first[:title].join("\n")}
152
+ #{@scenarios.first[:steps].join("\n")}
153
+ },@feature[:file])
154
+ @parser = @parser.parse
155
+ end
156
+
157
+ after(:all) do
158
+ @parser = nil
159
+ end
160
+
161
+ it_should_behave_like "a feature file"
162
+ it_should_behave_like "a feature file with a background"
163
+ it_should_behave_like "a feature file with scenarios"
164
+
165
+ end
166
+
167
+ context "feature file no background and multiple scenarios" do
168
+
169
+ before(:all) do
170
+
171
+ @feature = { :file => "ninja.strike.feature",
172
+ :name => "Ninja Feature Set",
173
+ :tags => [ "@kill", "@silently", "@sneak" ],
174
+ :description => ["This feature is going to save the company"] }
175
+
176
+ @scenarios = [
177
+ { :tags => ["@ninja"],
178
+ :title => ["Killing Scenario"],
179
+ :steps => [ "Given that there is an opponent",
180
+ "And a reason to fight him",
181
+ "When I karate strike him",
182
+ "Then I expect him to fall" ] },
183
+ { :tags => [],
184
+ :title => ["Dissappearing Scenario"],
185
+ :steps => [ "Given that I have defeated an opponent",
186
+ "And there are no more opponents",
187
+ "When I stop to take a breath",
188
+ "Then I expect to dissapear" ] } ]
189
+
190
+ @parser = FeatureParser.new(%{
191
+ #{@feature[:tags].join(" ")}
192
+ Feature: #{@feature[:name]}
193
+ #{@feature[:description].join("\n")}
194
+ #{@scenarios.collect {|scenario|
195
+ scenario[:tags].join(" ") +
196
+ "\nScenario: " + scenario[:title].join("\n") + "\n" +
197
+ scenario[:steps].join("\n")
198
+ }.join("\n")}},@feature[:file])
199
+ @parser = @parser.parse
200
+ end
201
+
202
+ after(:all) do
203
+ @parser = nil
204
+ end
205
+
206
+ it_should_behave_like "a feature file"
207
+ it_should_behave_like "a feature file with scenarios"
208
+
209
+ end
210
+
211
+
212
+
213
+ end
214
+
215
+ end
@@ -0,0 +1,128 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ module YARD::CodeObjects
4
+
5
+ describe YARD::CodeObjects do
6
+
7
+ shared_examples_for "CodeObjects" do
8
+ it "should respond to all defined attributes" do
9
+ @attributes.each {|attribute| @object.should respond_to(attribute) }
10
+ end
11
+ end
12
+
13
+ describe StepDefinitionObject do
14
+
15
+ before(:each) do
16
+ @attributes = [ :value, :keyword, :constants, :compare_value ]
17
+ @object = StepDefinitionObject.new(:root,:unique_name)
18
+ end
19
+
20
+ class TestObject
21
+ attr_accessor :name, :value
22
+ def initialize ; yield self ; end
23
+ end
24
+
25
+ it_should_behave_like "CodeObjects"
26
+
27
+ describe "compare_value" do
28
+
29
+ [ { :value => "/THERE (?:IS|ARE) THREE \#\{ CONSTANTS \} IN HERE \#\{ FOR\} YOU TO \#\{FIND \}",
30
+ :results => [ 'CONSTANTS', 'FOR', 'FIND' ] } ].each do |data|
31
+
32
+ it "should find all the constants within the step definition" do
33
+
34
+ stepdef = StepDefinitionObject.new(:root,"name")
35
+ stepdef.value = data[:value]
36
+
37
+
38
+ data[:results].each do |result|
39
+ stepdef._value_constants(data[:value]).should include(result)
40
+ stepdef._value_constants.should include(result)
41
+ end
42
+
43
+ end
44
+ end
45
+
46
+
47
+ [ { :value => "/WHEN THE \#\{NOUN\} HITS THE FAN/",
48
+ :constants => [ TestObject.new{|c| c.name = "NOUN" ; c.value = "/SMURF/" } ], :result => "WHEN THE SMURF HITS THE FAN" },
49
+
50
+ { :value => "/\#\{ SUBJECT \} WALK INTO THE \#\{ PLACE\} AND ASK THE \#\{PERSON \}/",
51
+ :constants => [ TestObject.new{|c| c.name = "SUBJECT" ; c.value = "/1 PERSON/" },
52
+ TestObject.new{|c| c.name = "PLACE" ; c.value = "/BAR/" },
53
+ TestObject.new{|c| c.name = "PERSON" ; c.value = "/BARTENDER/" } ],
54
+ :result => "1 PERSON WALK INTO THE BAR AND ASK THE BARTENDER" },
55
+
56
+ ].each do |data|
57
+
58
+ it "should replace all constants found within (#{data[:value]}) the value" do
59
+
60
+ stepdef = StepDefinitionObject.new(:root,"name")
61
+ stepdef.value = data[:value]
62
+ stepdef.constants = data[:constants]
63
+
64
+ stepdef.compare_value.should == data[:result]
65
+
66
+ end
67
+
68
+ end
69
+
70
+
71
+ end
72
+
73
+
74
+
75
+ end
76
+
77
+ describe StepTransformObject do
78
+
79
+ before(:each) do
80
+ @attributes = [ :value ]
81
+ @object = StepTransformObject.new(:root,:unique_name)
82
+ end
83
+
84
+ it_should_behave_like "CodeObjects"
85
+
86
+ end
87
+
88
+ end
89
+
90
+ end
91
+
92
+ module YARD::Handlers::Ruby::Legacy
93
+
94
+ describe YARD::Handlers::Ruby::Legacy do
95
+
96
+ shared_examples_for "Handlers" do
97
+ it "should match #{@match_criteria}" do
98
+ @handler::MATCH.should == @match_criteria
99
+ end
100
+
101
+ it "should respond to the method process" do
102
+ @handler.should respond_to(:process)
103
+ end
104
+
105
+ end
106
+
107
+ describe StepDefinitionHandler do
108
+ before(:each) do
109
+ @handler = StepDefinitionHandler
110
+ @match_criteria = /^((When|Given|And|Then)\s*(\/[^\/]+\/).+)$/
111
+ end
112
+
113
+ it_should_behave_like "Handlers"
114
+ end
115
+
116
+ describe StepTransformHandler do
117
+ before(:each) do
118
+ @handler = StepTransformHandler
119
+ @match_criteria = /^Transform\s*(\/[^\/]+\/).+$/
120
+ end
121
+
122
+ it_should_behave_like "Handlers"
123
+ end
124
+
125
+
126
+ end
127
+
128
+ end
@@ -0,0 +1,5 @@
1
+
2
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
3
+ $:.unshift(File.dirname(__FILE__))
4
+
5
+ require 'city'
data.tar.gz.sig ADDED
Binary file