rodakase 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +34 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +29 -0
  5. data/CHANGELOG.md +8 -0
  6. data/CODE_OF_CONDUCT.md +13 -0
  7. data/Gemfile +24 -0
  8. data/LICENSE +22 -0
  9. data/LICENSE.txt +22 -0
  10. data/README.md +114 -0
  11. data/Rakefile +4 -0
  12. data/benchmarks/templates/button.erb +1 -0
  13. data/benchmarks/view.rb +27 -0
  14. data/lib/roda/plugins/flow.rb +71 -0
  15. data/lib/rodakase.rb +8 -0
  16. data/lib/rodakase/application.rb +32 -0
  17. data/lib/rodakase/cli.rb +9 -0
  18. data/lib/rodakase/component.rb +40 -0
  19. data/lib/rodakase/config.rb +21 -0
  20. data/lib/rodakase/container.rb +127 -0
  21. data/lib/rodakase/transaction.rb +43 -0
  22. data/lib/rodakase/transaction/matcher.rb +31 -0
  23. data/lib/rodakase/transaction/result.rb +52 -0
  24. data/lib/rodakase/version.rb +3 -0
  25. data/lib/rodakase/view.rb +2 -0
  26. data/lib/rodakase/view/layout.rb +98 -0
  27. data/lib/rodakase/view/part.rb +53 -0
  28. data/lib/rodakase/view/renderer.rb +67 -0
  29. data/rodakase.gemspec +34 -0
  30. data/skeletons/simple/Gemfile +9 -0
  31. data/skeletons/simple/Rakefile +4 -0
  32. data/skeletons/simple/bin/console +6 -0
  33. data/skeletons/simple/config.ru +3 -0
  34. data/skeletons/simple/config/application.yml +4 -0
  35. data/skeletons/simple/core/boot.rb +12 -0
  36. data/skeletons/simple/core/simple/application.rb +16 -0
  37. data/skeletons/simple/core/simple/container.rb +11 -0
  38. data/skeletons/simple/core/simple/import.rb +9 -0
  39. data/skeletons/simple/lib/entities/user.rb +3 -0
  40. data/skeletons/simple/log/.gitkeep +0 -0
  41. data/skeletons/simple/spec/routes/heartbeat_spec.rb +9 -0
  42. data/skeletons/simple/spec/spec_helper.rb +12 -0
  43. data/skeletons/simple/spec/unit/user_spec.rb +17 -0
  44. data/skeletons/simple/spec/web_helper.rb +20 -0
  45. data/skeletons/simple/web/routes/root.rb +3 -0
  46. data/spec/dummy/apps/main/core/boot.rb +9 -0
  47. data/spec/dummy/apps/main/core/main/application.rb +17 -0
  48. data/spec/dummy/apps/main/core/main/container.rb +12 -0
  49. data/spec/dummy/apps/main/core/main/import.rb +9 -0
  50. data/spec/dummy/apps/main/core/main/requests.rb +21 -0
  51. data/spec/dummy/apps/main/core/main/view.rb +19 -0
  52. data/spec/dummy/apps/main/lib/entities/user.rb +3 -0
  53. data/spec/dummy/apps/main/lib/persistence/repositories/users.rb +14 -0
  54. data/spec/dummy/apps/main/lib/transaction.rb +11 -0
  55. data/spec/dummy/apps/main/lib/transactions/register_user.rb +17 -0
  56. data/spec/dummy/apps/main/lib/views/users/index.rb +15 -0
  57. data/spec/dummy/apps/main/requests/users.rb +5 -0
  58. data/spec/dummy/apps/main/web/routes/users.rb +21 -0
  59. data/spec/dummy/apps/main/web/templates/layouts/app.slim +6 -0
  60. data/spec/dummy/apps/main/web/templates/users/index.slim +3 -0
  61. data/spec/dummy/apps/main/web/templates/users/index/_list.slim +3 -0
  62. data/spec/dummy/apps/main/web/templates/users/index/_list_item.slim +1 -0
  63. data/spec/dummy/bin/console +6 -0
  64. data/spec/dummy/config.ru +3 -0
  65. data/spec/dummy/config/application.yml +4 -0
  66. data/spec/dummy/core/boot.rb +15 -0
  67. data/spec/dummy/core/dummy/container.rb +14 -0
  68. data/spec/dummy/core/dummy/import.rb +9 -0
  69. data/spec/dummy/lib/persistence/db.rb +13 -0
  70. data/spec/dummy/log/.gitkeep +0 -0
  71. data/spec/fixtures/templates/hello.slim +1 -0
  72. data/spec/fixtures/templates/layouts/app.slim +6 -0
  73. data/spec/fixtures/templates/shared/_index_table.slim +2 -0
  74. data/spec/fixtures/templates/shared/_shared_hello.slim +1 -0
  75. data/spec/fixtures/templates/tasks.slim +3 -0
  76. data/spec/fixtures/templates/user.slim +2 -0
  77. data/spec/fixtures/templates/users.slim +3 -0
  78. data/spec/fixtures/templates/users/_row.slim +2 -0
  79. data/spec/fixtures/templates/users/_tbody.slim +5 -0
  80. data/spec/fixtures/test/core/boot/bar.rb +5 -0
  81. data/spec/fixtures/test/lib/test/dep.rb +4 -0
  82. data/spec/fixtures/test/lib/test/foo.rb +5 -0
  83. data/spec/fixtures/test/lib/test/models.rb +4 -0
  84. data/spec/fixtures/test/lib/test/models/book.rb +6 -0
  85. data/spec/fixtures/test/lib/test/models/user.rb +6 -0
  86. data/spec/integration/application_spec.rb +21 -0
  87. data/spec/integration/transaction_spec.rb +85 -0
  88. data/spec/integration/view_spec.rb +65 -0
  89. data/spec/request/users_spec.rb +35 -0
  90. data/spec/spec_helper.rb +44 -0
  91. data/spec/support/helpers.rb +15 -0
  92. data/spec/unit/component_spec.rb +60 -0
  93. data/spec/unit/container_spec.rb +51 -0
  94. data/spec/unit/view/layout_spec.rb +49 -0
  95. data/spec/unit/view/part_spec.rb +55 -0
  96. data/spec/unit/view/renderer_spec.rb +29 -0
  97. metadata +359 -0
@@ -0,0 +1,6 @@
1
+ doctype html
2
+ html
3
+ head
4
+ title == page.title
5
+ body
6
+ == yield
@@ -0,0 +1,3 @@
1
+ h1 Users
2
+
3
+ .users == users.list
@@ -0,0 +1,3 @@
1
+ ul
2
+ - users.each do |user|
3
+ == user.list_item
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rodakase/cli'
4
+ # require_relative '../core/boot'
5
+
6
+ Rodakase::Cli.start
@@ -0,0 +1,3 @@
1
+ require_relative 'core/boot'
2
+
3
+ run Main::Application.freeze.app
@@ -0,0 +1,4 @@
1
+ development:
2
+ DATABASE_URL: 'postgres://localhost/rodakase'
3
+ test:
4
+ DATABASE_URL: 'postgres://localhost/rodakase'
@@ -0,0 +1,15 @@
1
+ require_relative 'dummy/container'
2
+
3
+ Dummy::Container.finalize! do |container|
4
+ require 'logger'
5
+ container.register(:logger, Logger.new(container.root.join('log/app.log')))
6
+
7
+ require 'rodakase/transaction'
8
+ container.register(:transaction, Rodakase::Transaction::Composer.new(container))
9
+
10
+ require 'persistence/db'
11
+ container.register(:db, Persistence::Db.new)
12
+ end
13
+
14
+ app_paths = Pathname(__FILE__).dirname.join('../apps').realpath.join('*')
15
+ Dir[app_paths].each { |f| require "#{f}/core/boot" }
@@ -0,0 +1,14 @@
1
+ require 'rodakase/container'
2
+
3
+ module Dummy
4
+ class Container < Rodakase::Container
5
+ # we need to override default here because we run tests from within the
6
+ # project root and our app is in spec/dummy
7
+ setting :root, Pathname(__FILE__).dirname.join('../..')
8
+ setting :auto_register, 'lib'
9
+
10
+ configure do
11
+ load_paths!('lib')
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,9 @@
1
+ require_relative 'container'
2
+
3
+ module Dummy
4
+ Import = Dummy::Container.import_module
5
+
6
+ def self.Import(*args)
7
+ Import[*args]
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ module Persistence
2
+ class Db
3
+ attr_reader :store
4
+
5
+ def initialize
6
+ @store = Hash.new { |k, v| k[v] = [] }
7
+ end
8
+
9
+ def [](name)
10
+ store[name]
11
+ end
12
+ end
13
+ end
File without changes
@@ -0,0 +1 @@
1
+ h1 Hello
@@ -0,0 +1,6 @@
1
+ doctype html
2
+ html
3
+ head
4
+ title == page.title
5
+ body
6
+ == yield
@@ -0,0 +1,2 @@
1
+ table
2
+ == yield
@@ -0,0 +1,3 @@
1
+ ol
2
+ - tasks.each do |task|
3
+ li == task[:title]
@@ -0,0 +1,2 @@
1
+ h1 = header[:title]
2
+ p = user[:name]
@@ -0,0 +1,3 @@
1
+ .users
2
+ == users.index_table do
3
+ == users.tbody
@@ -0,0 +1,2 @@
1
+ tr
2
+ == yield
@@ -0,0 +1,5 @@
1
+ tbody
2
+ - users.each do |user|
3
+ == user.row do
4
+ td = user[:name]
5
+ td = user[:email]
@@ -0,0 +1,5 @@
1
+ module Test
2
+ module Bar
3
+ # I shall be booted
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ module Test
2
+ class Dep
3
+ end
4
+ end
@@ -0,0 +1,5 @@
1
+ module Test
2
+ class Foo
3
+ include Import['test.dep']
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ module Test
2
+ module Models
3
+ end
4
+ end
@@ -0,0 +1,6 @@
1
+ module Test
2
+ module Models
3
+ class Book
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Test
2
+ module Models
3
+ class User
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,21 @@
1
+ require 'main/import'
2
+
3
+ RSpec.describe 'Rodakase Application' do
4
+ it 'sets env' do
5
+ expect(Main::Application.config.container.config.env).to be(:test)
6
+ end
7
+
8
+ it 'loads container' do
9
+ expect(Main::Application[:logger]).to be_instance_of(Logger)
10
+ end
11
+
12
+ it 'sets up namespaced dependencies' do
13
+ expect(Main::Application['persistence.repositories.users']).to be_instance_of(Persistence::Repositories::Users)
14
+ end
15
+
16
+ it 'sets up auto-injection mechanism' do
17
+ klass = Class.new { include Main::Import(:logger) }
18
+
19
+ expect(klass.new.logger).to be_instance_of(Logger)
20
+ end
21
+ end
@@ -0,0 +1,85 @@
1
+ require 'rodakase/transaction'
2
+
3
+ RSpec.describe 'Rodakase Transaction' do
4
+ subject(:transaction) { Rodakase::Transaction::Composer.new(container) }
5
+
6
+ let(:container) do
7
+ {
8
+ validate_params: -> params {
9
+ if params[:email]
10
+ Rodakase::Transaction::Success(params)
11
+ else
12
+ Rodakase::Transaction::Failure(:validation, 'missing email')
13
+ end
14
+ },
15
+ persist_user: -> input {
16
+ input.fmap do |value|
17
+ Test::DB.concat([value])
18
+ end
19
+ },
20
+ render_ui: -> input {
21
+ input.fmap do |db|
22
+ "user #{db.last[:email]} created"
23
+ end
24
+ }
25
+ }
26
+ end
27
+
28
+ let(:pipeline) do
29
+ transaction.define do
30
+ step :validate_params do
31
+ step :persist_user, publish: true do
32
+ step :render_ui
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ before do
39
+ module Test
40
+ DB = []
41
+ end
42
+ end
43
+
44
+ it 'works with success' do
45
+ result = []
46
+
47
+ pipeline.(email: 'jane@doe.org') do |m|
48
+ m.success do |value|
49
+ result << value
50
+ end
51
+ end
52
+
53
+ expect(result).to include('user jane@doe.org created')
54
+ end
55
+
56
+ it 'works with failure' do
57
+ result = []
58
+
59
+ pipeline.(foo: 'jane@doe.org') do |m|
60
+ m.failure do |f|
61
+ f.on(:validation) do |err|
62
+ result << err
63
+ end
64
+ end
65
+ end
66
+
67
+ expect(result).to include('missing email')
68
+ end
69
+
70
+ it 'works with publisher' do
71
+ Test::NOTIFICATIONS = []
72
+
73
+ module Test::Listener
74
+ def self.persist_user_success(result)
75
+ result.fmap { |db| Test::NOTIFICATIONS << db.last }
76
+ end
77
+ end
78
+
79
+ pipeline.subscribe(persist_user: Test::Listener)
80
+
81
+ pipeline.(email: 'jane@doe.org')
82
+
83
+ expect(Test::NOTIFICATIONS).to include(email: 'jane@doe.org')
84
+ end
85
+ end
@@ -0,0 +1,65 @@
1
+ require 'rodakase/view'
2
+
3
+ RSpec.describe 'Rodakase View' do
4
+ let(:view_class) do
5
+ klass = Class.new(Rodakase::View::Layout)
6
+
7
+ klass.configure do |config|
8
+ config.renderer = renderer
9
+ config.engine = :slim
10
+ config.name = 'app'
11
+ config.template = 'users'
12
+ end
13
+
14
+ klass
15
+ end
16
+
17
+ let(:renderer) do
18
+ Rodakase::View::Renderer.new(SPEC_ROOT.join('fixtures/templates'), engine: :slim)
19
+ end
20
+
21
+ let(:scope) do
22
+ Struct.new(:title).new('Rodakase Rocks!')
23
+ end
24
+
25
+ it 'renders within a layout using provided scope' do
26
+ view = view_class.new
27
+
28
+ users = [
29
+ { name: 'Jane', email: 'jane@doe.org' },
30
+ { name: 'Joe', email: 'joe@doe.org' }
31
+ ]
32
+
33
+ expect(view.(scope: scope, locals: { users: users })).to eql(
34
+ '<!DOCTYPE html><html><head><title>Rodakase Rocks!</title></head><body><div class="users"><table><tbody><tr><td>Jane</td><td>jane@doe.org</td></tr><tr><td>Joe</td><td>joe@doe.org</td></tr></tbody></table></div></body></html>'
35
+ )
36
+ end
37
+
38
+ describe 'inheritance' do
39
+ let(:parent_view) do
40
+ klass = Class.new(Rodakase::View::Layout)
41
+
42
+ klass.setting :renderer, renderer
43
+ klass.setting :engine, :slim
44
+ klass.setting :name, 'app'
45
+
46
+ klass
47
+ end
48
+
49
+ let(:child_view) do
50
+ Class.new(parent_view) do
51
+ configure do |config|
52
+ config.template = 'tasks'
53
+ end
54
+ end
55
+ end
56
+
57
+ it 'renders within a parent class layout using provided scope' do
58
+ view = child_view.new
59
+
60
+ expect(view.(scope: scope, locals: { tasks: [{ title: 'one' }, { title: 'two' }] })).to eql(
61
+ '<!DOCTYPE html><html><head><title>Rodakase Rocks!</title></head><body><ol><li>one</li><li>two</li></ol></body></html>'
62
+ )
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,35 @@
1
+ require 'entities/user'
2
+
3
+ RSpec.describe '/users', type: :request do
4
+ describe 'GET /users' do
5
+ it 'renders hello template' do
6
+ get '/users'
7
+
8
+ expect(last_response).to be_ok
9
+
10
+ expect(last_response.body).to eql(
11
+ '<!DOCTYPE html><html><head><title>Woohaa</title></head><body><h1>Users</h1><div class="users"><ul><li>Jane</li><li>Joe</li></ul></div></body></html>'
12
+ )
13
+ end
14
+ end
15
+
16
+ describe 'POST /users' do
17
+ it 'creates a user' do
18
+ user = { id: '1', name: 'Jane' }
19
+
20
+ post '/users', user: user
21
+
22
+ expect(last_response).to be_created
23
+
24
+ expect(container['persistence.repositories.users'].all).to eql([Entities::User.new('1', 'Jane')])
25
+ end
26
+
27
+ it 'redirects when name is missing' do
28
+ user = { id: '1' }
29
+
30
+ post '/users', user: user
31
+
32
+ expect(last_response).to be_redirect
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,44 @@
1
+ # encoding: utf-8
2
+
3
+ if RUBY_ENGINE == "rbx"
4
+ require "codeclimate-test-reporter"
5
+ CodeClimate::TestReporter.start
6
+ end
7
+
8
+ begin
9
+ require 'byebug'
10
+ rescue LoadError; end
11
+
12
+ require 'rack/test'
13
+ require 'slim'
14
+
15
+ ENV['RACK_ENV'] = 'test'
16
+
17
+ SPEC_ROOT = Pathname(__FILE__).dirname
18
+
19
+ Dir[SPEC_ROOT.join('support/*.rb').to_s].each { |f| require f }
20
+ Dir[SPEC_ROOT.join('shared/*.rb').to_s].each { |f| require f }
21
+
22
+ require SPEC_ROOT.join('dummy/core/boot').to_s
23
+
24
+ module Test; end
25
+
26
+ RSpec.configure do |config|
27
+ config.disable_monkey_patching!
28
+
29
+ config.before(:suite) do
30
+ Main::Application.freeze
31
+ end
32
+
33
+ config.include Rack::Test::Methods, type: :request
34
+ config.include Helpers
35
+
36
+ config.before do
37
+ @test_constants = Test.constants
38
+ end
39
+
40
+ config.after do
41
+ added_constants = Test.constants - @test_constants
42
+ added_constants.each { |name| Test.send(:remove_const, name) }
43
+ end
44
+ end
@@ -0,0 +1,15 @@
1
+ module Helpers
2
+ module_function
3
+
4
+ def fixtures_path
5
+ SPEC_ROOT.join('fixtures')
6
+ end
7
+
8
+ def container
9
+ Dummy::Container
10
+ end
11
+
12
+ def app
13
+ Main::Application.app
14
+ end
15
+ end