hobby 0.0.12 → 0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2d2d480ccdf4a60839072589bfaa58309a00bf4a
4
- data.tar.gz: e69b2439193e69c2f53adc780dac6666f71a01e6
3
+ metadata.gz: 1c820bc2f67ffcbd87d4de89a2e8ad53a6f83da9
4
+ data.tar.gz: e56880e61b2d283537bf44bd019709440dde9118
5
5
  SHA512:
6
- metadata.gz: ff31f1f11344235dec85b8d021008a1b89a18ab65b8e4743add83b8e8e8e3104af567c8bdb01a5e84d6a78c5c9248a95272e3de7f3ac88fc6c60180a3e7266ee
7
- data.tar.gz: 723ba318c713c9d21c44c3bf8397e48a7204a562c7294545aedd7a26634a402887269878618cc61e91b3a2dcbe3454a0aa590dfde07f1cc51532c0d8123a0f2f
6
+ metadata.gz: f14f9c47364424a1826184cd11a670eed4509e315bb83b6f978e05022fd17da57d3fc139d1e40c62ea33c06ebf59c38996f4dfb90ea0bef779b2a67b837321b5
7
+ data.tar.gz: 27b2ac428b2a8a7b51941a4e4dd7bab6d9c28e1cbbb4e77d49c282ce58638e0500913b6320f2090511a4a5ca7793b9ba1afd9099748ba17b67afde31214b3142
data/Gemfile CHANGED
@@ -1,7 +1,7 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'devtools', github: 'mbj/devtools'
4
- gem 'mutant', github: 'mbj/mutant'
3
+ gem 'devtools'
4
+ gem 'mutant'
5
5
  gem 'minitest'
6
6
  gem 'minitest-power_assert'
7
7
  gem 'rack-test'
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = 'hobby'
7
- spec.version = '0.0.12'
7
+ spec.version = '0.1.0'
8
8
  spec.authors = ['Anatoly Chernow']
9
9
  spec.email = ['chertoly@gmail.com']
10
10
  spec.summary = %q{A minimal DSL over rack}
@@ -10,20 +10,19 @@ module Hobby
10
10
 
11
11
  def self.included app
12
12
  app.extend Singleton
13
- app.builder, app.router = Rack::Builder.new, Router.new
13
+ app.router = Router.new
14
14
  app.request, app.response = Rack::Request, Rack::Response
15
15
  end
16
16
 
17
17
  module Singleton
18
- attr_accessor :builder, :router, :request, :response
18
+ attr_accessor :router, :request, :response
19
19
 
20
20
  def new (*)
21
- builder.run super
22
- builder.to_app
21
+ super.router.to_rack_app
23
22
  end
24
23
 
25
24
  extend Forwardable
26
- delegate [:map, :use] => :builder
25
+ delegate [:map, :use] => :router
27
26
 
28
27
  VERBS.each do |verb|
29
28
  define_method verb.downcase do |path = '/', &action|
@@ -41,7 +40,7 @@ module Hobby
41
40
  protected
42
41
  def handle env
43
42
  catch :halt do
44
- @route = self.class.router.route_for (@env = env)
43
+ @route = router.route_for (@env = env)
45
44
  fill_body
46
45
  response
47
46
  end
@@ -1,7 +1,19 @@
1
1
  module Hobby
2
2
  module Helpers
3
+ extend Forwardable
4
+
3
5
  attr_reader :env, :route
4
6
 
7
+ def router
8
+ @router ||= begin
9
+ router = self.class.router.clone
10
+ router.app = self
11
+ router
12
+ end
13
+ end
14
+
15
+ delegate [:map, :use] => :router
16
+
5
17
  def request
6
18
  @request ||= self.class.request.new env
7
19
  end
@@ -2,6 +2,12 @@ module Hobby
2
2
  class Router
3
3
  def initialize
4
4
  @routes = Routes.new
5
+ @uses, @maps = [], []
6
+ end
7
+
8
+ def initialize_copy _router
9
+ @uses = instance_variable_get(:@uses).dup
10
+ @maps = instance_variable_get(:@maps).dup
5
11
  end
6
12
 
7
13
  def add_route verb, path, &action
@@ -17,8 +23,33 @@ module Hobby
17
23
  route, params = @routes["#{env['REQUEST_METHOD']}#{env['PATH_INFO']}"]
18
24
  params ? route.with_params(params) : route
19
25
  end
26
+
27
+ def use *all
28
+ @uses << all
29
+ end
30
+
31
+ def map path, app = nil, &block
32
+ @maps << Builder::Map.new(path, app, &block)
33
+ end
34
+
35
+ attr_accessor :app
36
+
37
+ def to_rack_app
38
+ builder = create_builder
39
+ builder.run app
40
+ builder.to_app
41
+ end
42
+
43
+ private
44
+ def create_builder
45
+ builder = Builder.new
46
+ @uses.each { |all| builder.add_use *all }
47
+ @maps.each { |map| builder.add_map map }
48
+ builder
49
+ end
20
50
  end
21
51
  end
22
52
 
53
+ require 'hobby/router/builder'
23
54
  require 'hobby/router/routes'
24
55
  require 'hobby/router/route'
@@ -0,0 +1,25 @@
1
+ module Hobby
2
+ class Router
3
+ class Builder < Rack::Builder
4
+ # To work around
5
+ # https://github.com/mbj/mutant#the-crash--stuck-problem-mri
6
+ alias add_use use
7
+ alias add_map2 map
8
+
9
+ def add_map map
10
+ if map.app
11
+ add_map2 map.path do run map.app end
12
+ else
13
+ add_map2 map.path, &map.block
14
+ end
15
+ end
16
+
17
+ class Map
18
+ attr_reader :path, :app, :block
19
+ def initialize path, app, &block
20
+ @path, @app, @block = path, app, block
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -285,8 +285,8 @@ to '/anatoly' and '/patricio' routes:
285
285
  class App
286
286
  include Hobby
287
287
 
288
- map('/anatoly') { run C.new 'Anatoly' }
289
- map('/patricio') { run C.new 'Patricio' }
288
+ map '/anatoly', C.new('Anatoly')
289
+ map '/patricio', C.new('Patricio')
290
290
 
291
291
  get '/' do
292
292
  'Mapping app.'
@@ -327,7 +327,6 @@ Many components of an application can be customized or replaced.
327
327
  class App
328
328
  include Hobby
329
329
 
330
- self.builder = custom_builder
331
330
  self.router = custom_router
332
331
  self.request = custom_request
333
332
  self.response = custom_response
@@ -75,6 +75,17 @@ describe Hobby::App do
75
75
  end
76
76
  end
77
77
 
78
+ describe '#router' do
79
+ it 'gives a distinct router to each app' do
80
+ app = Class.new { include Hobby }
81
+
82
+ first_instance = app.new
83
+ second_instance = app.new
84
+
85
+ assert { not first_instance.router.equal? second_instance.router }
86
+ end
87
+ end
88
+
78
89
  describe :integration do
79
90
  before do
80
91
  described_class.app = build_app described_class
@@ -89,6 +100,51 @@ describe Hobby::App do
89
100
  get '/map'
90
101
  assert { last_response.body == 'from map' }
91
102
  end
103
+
104
+ it 'mounts an application to the rack stack with old deprecated syntax' do
105
+ get '/deprecated_map'
106
+ assert { last_response.body == 'from deprecated map' }
107
+ end
108
+ end
109
+
110
+ describe MapInsideInitialize do
111
+ describe 'without any passed arguments' do
112
+ def app
113
+ described_class.app.new
114
+ end
115
+
116
+ it do
117
+ get '/'
118
+ assert { last_response.body == 'hello world' }
119
+ get '/first_map'
120
+ assert { last_response.body == 'first mapapp' }
121
+ get '/second_map'
122
+ assert { last_response.body == 'second mapapp' }
123
+ end
124
+ end
125
+
126
+ describe 'with passed routes' do
127
+ def app
128
+ some_app = Class.new {
129
+ include Hobby
130
+ get { 'Some string.' }
131
+ }
132
+ routes = { '/third_map' => some_app.new }
133
+ described_class.app.new routes
134
+ end
135
+
136
+ it do
137
+ get '/'
138
+ assert { last_response.body == 'hello world' }
139
+ get '/first_map'
140
+ assert { last_response.body == 'first mapapp' }
141
+ get '/second_map'
142
+ assert { last_response.body == 'second mapapp' }
143
+
144
+ get '/third_map'
145
+ assert { last_response.body == 'Some string.' }
146
+ end
147
+ end
92
148
  end
93
149
 
94
150
  describe Use do
@@ -98,6 +154,13 @@ describe Hobby::App do
98
154
  end
99
155
  end
100
156
 
157
+ describe UseInsideInitialize do
158
+ it do
159
+ get '/'
160
+ assert { last_response.content_type == 'application/json' }
161
+ end
162
+ end
163
+
101
164
  describe WithoutPath do
102
165
  it 'is accessible as /' do
103
166
  get '/'
@@ -171,5 +234,43 @@ describe Hobby::App do
171
234
  assert { last_response.body == 'Created.' }
172
235
  end
173
236
  end
237
+
238
+ describe UnshareableRouterMaps do
239
+ it do
240
+ get '/1/first'
241
+ assert { last_response.body == 'The name is A.' }
242
+ get '/1/second'
243
+ assert { last_response.body == 'The name is B.' }
244
+ get '/1/third'
245
+ assert { last_response.body == '404' }
246
+
247
+ get '/2/first'
248
+ assert { last_response.body == 'The name is A.' }
249
+ get '/2/second'
250
+ assert { last_response.body == 'The name is B.' }
251
+ get '/2/third'
252
+ assert { last_response.body == 'The name is C.' }
253
+
254
+ get '/3/first'
255
+ assert { last_response.body == 'The name is A.' }
256
+ get '/3/second'
257
+ assert { last_response.body == 'The name is B.' }
258
+ get '/3/third'
259
+ assert { last_response.body == '404' }
260
+ end
261
+ end
262
+
263
+ describe UnshareableRouterUses do
264
+ it do
265
+ get '/1'
266
+ assert { last_response.content_type == 'application/html' }
267
+
268
+ get '/2'
269
+ assert { last_response.content_type == 'application/json' }
270
+
271
+ get '/3'
272
+ assert { last_response.content_type == 'application/html' }
273
+ end
274
+ end
174
275
  end
175
276
  end
@@ -1,5 +1,5 @@
1
- map '/map' do
2
- run Proc.new { |env| [200, {}, ['from map']] }
1
+ map '/map', Proc.new { |env| [200, {}, ['from map']] }
2
+ map '/deprecated_map' do
3
+ run Proc.new { |env| [200, {}, ['from deprecated map']] }
3
4
  end
4
-
5
5
  get('/') { 'hello world' }
@@ -0,0 +1,13 @@
1
+ first_app = Proc.new { |env| [200, {}, ['first mapapp']] }
2
+ second_app = Proc.new { |env| [200, {}, ['second mapapp']] }
3
+
4
+ map '/first_map', first_app
5
+ map '/second_map', second_app
6
+
7
+ get('/') { 'hello world' }
8
+
9
+ def initialize hash = {}
10
+ hash.each do |route, app|
11
+ map route, app
12
+ end
13
+ end
@@ -1,17 +1,15 @@
1
- map('/nested') do
2
- nested_app = Class.new do
3
- include Hobby::App
1
+ nested_app = Class.new do
2
+ include Hobby::App
4
3
 
5
- def initialize first, second
6
- @a = first
7
- @b = second
8
- @c = yield
9
- end
10
-
11
- get do
12
- "#{@a}:#{@b}:#{@c}"
13
- end
4
+ def initialize first, second
5
+ @a = first
6
+ @b = second
7
+ @c = yield
14
8
  end
15
9
 
16
- run nested_app.new(:a, :b) { :c }
10
+ get do
11
+ "#{@a}:#{@b}:#{@c}"
12
+ end
17
13
  end
14
+
15
+ map '/nested', nested_app.new(:a, :b) { :c }
@@ -5,4 +5,12 @@ self.router = Class.new {
5
5
  def route_for _request
6
6
  -> { 'for any route' }
7
7
  end
8
+
9
+ attr_accessor :app
10
+
11
+ def to_rack_app
12
+ builder = Rack::Builder.new
13
+ builder.run app
14
+ builder.to_app
15
+ end
8
16
  }.new
@@ -0,0 +1,29 @@
1
+ mapped_app = Class.new do
2
+ include Hobby
3
+
4
+ def initialize name
5
+ @name = name
6
+ end
7
+
8
+ get { "The name is #{@name}." }
9
+ end
10
+
11
+ mapping_app = Class.new do
12
+ include Hobby
13
+
14
+ map '/first', mapped_app.new('A')
15
+ map '/second', mapped_app.new('B')
16
+
17
+ def initialize routes = {}
18
+ routes.each do |route, app|
19
+ map route, app
20
+ end
21
+ end
22
+ end
23
+
24
+ map '/1', mapping_app.new
25
+
26
+ routes = { '/third' => mapped_app.new('C') }
27
+ map '/2', mapping_app.new(routes)
28
+
29
+ map '/3', mapping_app.new
@@ -0,0 +1,16 @@
1
+ require 'json'
2
+
3
+ app = Class.new do
4
+ include Hobby
5
+ get { 'hello world'.to_json }
6
+
7
+ use Rack::ContentType, 'application/html'
8
+
9
+ def initialize middleware_with_arguments = nil
10
+ use *middleware_with_arguments if middleware_with_arguments
11
+ end
12
+ end
13
+
14
+ map '/1', app.new
15
+ map '/2', app.new([Rack::ContentType, 'application/json'])
16
+ map '/3', app.new
@@ -0,0 +1,7 @@
1
+ require 'json'
2
+
3
+ get { 'hello world'.to_json }
4
+
5
+ def initialize
6
+ use Rack::ContentType, 'application/json'
7
+ end
@@ -12,8 +12,34 @@ if defined? Mutant
12
12
  integration.all_tests
13
13
  end
14
14
  end
15
+
16
+ class Mutant::Isolation::Fork
17
+ def result
18
+ yield
19
+ end
20
+ end
21
+
22
+ class Mutant::Loader
23
+ def call
24
+ source = Unparser.unparse node
25
+
26
+ puts <<~S
27
+ Current mutantion:
28
+ #{source}
29
+ S
30
+
31
+ kernel.eval source, binding, subject.source_path.to_s, subject.source_line
32
+ end
33
+ end
34
+ end
35
+
36
+ module EnvFor
37
+ def env_for path, verb = 'GET'
38
+ {'REQUEST_METHOD' => verb, 'PATH_INFO' => path }
39
+ end
15
40
  end
16
41
 
17
42
  RSpec.configure do |config|
18
43
  config.expect_with :rspec, :minitest
44
+ config.include EnvFor
19
45
  end
@@ -2,10 +2,6 @@ module RouterMatchers
2
2
  extend self
3
3
  SOME_ROUTE = ->{:some_route}
4
4
 
5
- def env_for path, verb = 'GET'
6
- {'REQUEST_METHOD' => verb, 'PATH_INFO' => path }
7
- end
8
-
9
5
  def add_routes *routes
10
6
  routes.each { |route| subject.add_route 'GET', route, &SOME_ROUTE }
11
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hobby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.12
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anatoly Chernow
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-07-23 00:00:00.000000000 Z
11
+ date: 2017-09-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -39,6 +39,7 @@ files:
39
39
  - lib/hobby.rb
40
40
  - lib/hobby/helpers.rb
41
41
  - lib/hobby/router.rb
42
+ - lib/hobby/router/builder.rb
42
43
  - lib/hobby/router/route.rb
43
44
  - lib/hobby/router/routes.rb
44
45
  - readme.adoc
@@ -49,10 +50,14 @@ files:
49
50
  - spec/apps/Halting.rb
50
51
  - spec/apps/Main.rb
51
52
  - spec/apps/Map.rb
53
+ - spec/apps/MapInsideInitialize.rb
52
54
  - spec/apps/Nested.rb
53
55
  - spec/apps/OneRouteRouter.rb
54
56
  - spec/apps/Status.rb
57
+ - spec/apps/UnshareableRouterMaps.rb
58
+ - spec/apps/UnshareableRouterUses.rb
55
59
  - spec/apps/Use.rb
60
+ - spec/apps/UseInsideInitialize.rb
56
61
  - spec/apps/WithoutPath.rb
57
62
  - spec/helper.rb
58
63
  - spec/router_matchers.rb
@@ -77,7 +82,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
77
82
  version: '0'
78
83
  requirements: []
79
84
  rubyforge_project:
80
- rubygems_version: 2.6.11
85
+ rubygems_version: 2.6.13
81
86
  signing_key:
82
87
  specification_version: 4
83
88
  summary: A minimal DSL over rack
@@ -89,10 +94,14 @@ test_files:
89
94
  - spec/apps/Halting.rb
90
95
  - spec/apps/Main.rb
91
96
  - spec/apps/Map.rb
97
+ - spec/apps/MapInsideInitialize.rb
92
98
  - spec/apps/Nested.rb
93
99
  - spec/apps/OneRouteRouter.rb
94
100
  - spec/apps/Status.rb
101
+ - spec/apps/UnshareableRouterMaps.rb
102
+ - spec/apps/UnshareableRouterUses.rb
95
103
  - spec/apps/Use.rb
104
+ - spec/apps/UseInsideInitialize.rb
96
105
  - spec/apps/WithoutPath.rb
97
106
  - spec/helper.rb
98
107
  - spec/router_matchers.rb