rodakase 0.0.1

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 (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