rung 0.0.1.pre.alpha → 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +72 -0
  3. data/.config/cucumber.yml +1 -0
  4. data/.gitignore +3 -0
  5. data/.rspec +0 -1
  6. data/.rubocop.yml +22 -0
  7. data/Gemfile +6 -2
  8. data/Gemfile.lock +23 -1
  9. data/README.adoc +111 -0
  10. data/Rakefile +19 -4
  11. data/features/{steps_definition.feature → 010_operation.feature} +29 -6
  12. data/features/{state.feature → 020_state.feature} +17 -4
  13. data/features/{failure.feature → 030_failure.feature} +29 -6
  14. data/features/040_failure_step.feature +118 -0
  15. data/features/050_other_steps.feature +135 -0
  16. data/features/051_fail_fast.feature +66 -0
  17. data/features/060_step_wrappers.feature +170 -0
  18. data/features/070_operation_wrappers.feature +41 -0
  19. data/features/080_exceptions_handling.feature +57 -0
  20. data/features/090_around_step_wrapper.feature +130 -0
  21. data/features/200_misc.feature +18 -0
  22. data/features/step_definitions/output.rb +8 -3
  23. data/features/step_definitions/temporary_code_scope.rb +8 -7
  24. data/lib/rung.rb +7 -6
  25. data/lib/rung/definition/callback.rb +14 -0
  26. data/lib/rung/definition/nested_step.rb +16 -0
  27. data/lib/rung/definition/operation_dsl.rb +31 -0
  28. data/lib/rung/definition/step.rb +43 -0
  29. data/lib/rung/definition/steps_dsl.rb +33 -18
  30. data/lib/rung/{base.rb → operation.rb} +3 -2
  31. data/lib/rung/runner/call_helper.rb +30 -12
  32. data/lib/rung/runner/run_context.rb +23 -6
  33. data/lib/rung/runner/runner.rb +34 -14
  34. data/lib/rung/state.rb +35 -0
  35. data/lib/rung/value_object.rb +12 -0
  36. data/lib/rung/version.rb +1 -1
  37. data/rung.gemspec +15 -16
  38. data/target/cukedoctor-intro.adoc +1 -0
  39. data/target/cukedoctor.css +3 -0
  40. metadata +39 -23
  41. data/README.md +0 -79
  42. data/lib/rung/definition/steps/nested_step.rb +0 -20
  43. data/lib/rung/definition/steps/step.rb +0 -30
  44. data/lib/rung/definition/steps_definition.rb +0 -13
  45. data/lib/rung/runner/result.rb +0 -24
  46. data/lib/rung/runner/run_state.rb +0 -12
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a7cd0b72e47764f703e416e708f76644255e53df
4
- data.tar.gz: 7887c8167710d0c089c792ca25c53a79b2fe053a
3
+ metadata.gz: de22a1e77fdae3c25ffd7813dfd6ffa2059d636a
4
+ data.tar.gz: dd81b258d16d75fa76d68cf2a72875c9c595db8f
5
5
  SHA512:
6
- metadata.gz: 15ad2faba325fe974e782ac1941255e0ab80b2dddf269d77892d30a0ebb4a99e67844978b5dbc5dc7ad8c3ec97cd222e2e80ca3536ea6d9e2753ba4a1ee9f8e3
7
- data.tar.gz: bb56850efb181213e11bae971feea9f659408f668598d1994bde7be06eba32010b2cd9603eb490c5b4c5640c13976ec7318ae03404b5511029d5cda924072248
6
+ metadata.gz: 2230826da27de68cc4d14a6678ce25fbc8a931e518df1931ad3fa5f5099d8e541ee53a0a1f244b14381bff623d03769d0e6a183611f9f0b59c9ea5259ad41b85
7
+ data.tar.gz: 5f2a503861595ecd5aa133ea523214fb2d5be738521b440fa27b1270d6a1ae422b13ef9b0fa078e2ed0b08a60ea42211dfad3f59652c4ccf6f4e4d5477fbc3db
@@ -0,0 +1,72 @@
1
+ version: 2
2
+ jobs:
3
+ build:
4
+ docker:
5
+ - image: circleci/ruby:2.4.1
6
+ steps:
7
+ - checkout
8
+ - run: bundle install
9
+ - run: bundle exec rspec
10
+ - run: bundle exec cucumber
11
+ - run: bundle exec rubocop
12
+
13
+ - run: mkdir workspace
14
+ - run: bundle exec cucumber -f json -o workspace/cucumber.json
15
+ - persist_to_workspace:
16
+ root: workspace
17
+ paths:
18
+ - cucumber.json
19
+
20
+ build_docs:
21
+ docker:
22
+ - image: circleci/openjdk:11-jdk-browsers
23
+ steps:
24
+ - checkout
25
+ - attach_workspace:
26
+ at: /tmp/workspace
27
+ - run: wget https://bintray.com/artifact/download/rmpestano/cukedoctor/com/github/cukedoctor/cukedoctor-main/1.2.1/cukedoctor-main-1.2.1.jar
28
+ - run: mkdir /tmp/workspace/generated_doc
29
+ - run: java -jar cukedoctor-main-1.2.1.jar -f html5 -p /tmp/workspace/cucumber.json -o /tmp/workspace/generated_doc/index -hideSummarySection -t "Rung Documentation" -hideStepTime -hideScenarioKeyword -hideFeaturesSection
30
+ - persist_to_workspace:
31
+ root: /tmp/workspace/
32
+ paths:
33
+ - generated_doc
34
+
35
+ deploy_docs:
36
+ docker:
37
+ - image: node:8.10.0
38
+ steps:
39
+ - checkout
40
+ - attach_workspace:
41
+ at: workspace
42
+ - run:
43
+ name: Install and configure dependencies
44
+ command: |
45
+ npm install -g --silent gh-pages@2.0.1
46
+ git config user.email "circle-ci@jedrychowski.org"
47
+ git config user.name "ci-build"
48
+ - add_ssh_keys:
49
+ fingerprints:
50
+ - "32:c9:81:d7:bf:fb:82:c1:48:eb:fc:a8:98:f8:48:7e"
51
+ - run:
52
+ name: Deploy docs to gh-pages branch
53
+ command: gh-pages --dist workspace/generated_doc/ --message "[skip ci] Doc update"
54
+
55
+ workflows:
56
+ version: 2
57
+
58
+ btd:
59
+ jobs:
60
+ - build
61
+ - build_docs:
62
+ requires:
63
+ - build
64
+ filters:
65
+ branches:
66
+ only: master
67
+ - deploy_docs:
68
+ requires:
69
+ - build_docs
70
+ filters:
71
+ branches:
72
+ only: master
@@ -0,0 +1 @@
1
+ default: --format progress
@@ -0,0 +1,3 @@
1
+ tmp
2
+ generated_doc/
3
+ .yardoc
data/.rspec CHANGED
@@ -1,3 +1,2 @@
1
- --format documentation
2
1
  --color
3
2
  --require spec_helper
@@ -0,0 +1,22 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.3
3
+ Exclude:
4
+ - spec/integration/*
5
+ - rung.gemspec
6
+
7
+ Style/FrozenStringLiteralComment:
8
+ Enabled: false
9
+
10
+ Style/Documentation:
11
+ Enabled: false
12
+
13
+ Metrics/BlockLength:
14
+ Exclude:
15
+ - 'spec/**/*.rb'
16
+
17
+ Layout/AlignParameters:
18
+ EnforcedStyle: with_fixed_indentation
19
+
20
+ Metrics/LineLength:
21
+ IgnoredPatterns:
22
+ - ^\s*it \'
data/Gemfile CHANGED
@@ -1,7 +1,11 @@
1
- source "https://rubygems.org"
1
+ source 'https://rubygems.org'
2
2
 
3
- git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
3
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
4
4
 
5
5
  # Specify your gem's dependencies in rung.gemspec
6
6
  gemspec
7
7
  gem 'pry'
8
+
9
+ gem 'asciidoctor'
10
+ gem 'rubocop'
11
+ gem 'yard'
@@ -1,11 +1,13 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rung (0.0.1.pre.alpha)
4
+ rung (0.1)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
+ asciidoctor (1.5.8)
10
+ ast (2.4.0)
9
11
  backports (3.11.4)
10
12
  builder (3.2.3)
11
13
  coderay (1.1.2)
@@ -27,12 +29,18 @@ GEM
27
29
  cucumber-wire (0.0.1)
28
30
  diff-lcs (1.3)
29
31
  gherkin (5.1.0)
32
+ jaro_winkler (1.5.2)
30
33
  method_source (0.9.2)
31
34
  multi_json (1.13.1)
32
35
  multi_test (0.1.2)
36
+ parallel (1.13.0)
37
+ parser (2.6.0.0)
38
+ ast (~> 2.4.0)
39
+ powerpack (0.1.2)
33
40
  pry (0.12.2)
34
41
  coderay (~> 1.1.0)
35
42
  method_source (~> 0.9.0)
43
+ rainbow (3.0.0)
36
44
  rake (10.5.0)
37
45
  rspec (3.8.0)
38
46
  rspec-core (~> 3.8.0)
@@ -47,17 +55,31 @@ GEM
47
55
  diff-lcs (>= 1.2.0, < 2.0)
48
56
  rspec-support (~> 3.8.0)
49
57
  rspec-support (3.8.0)
58
+ rubocop (0.63.1)
59
+ jaro_winkler (~> 1.5.1)
60
+ parallel (~> 1.10)
61
+ parser (>= 2.5, != 2.5.1.1)
62
+ powerpack (~> 0.1)
63
+ rainbow (>= 2.2.2, < 4.0)
64
+ ruby-progressbar (~> 1.7)
65
+ unicode-display_width (~> 1.4.0)
66
+ ruby-progressbar (1.10.0)
67
+ unicode-display_width (1.4.1)
68
+ yard (0.9.18)
50
69
 
51
70
  PLATFORMS
52
71
  ruby
53
72
 
54
73
  DEPENDENCIES
74
+ asciidoctor
55
75
  bundler (~> 1.16)
56
76
  cucumber (~> 3.1)
57
77
  pry
58
78
  rake (~> 10.0)
59
79
  rspec (~> 3.0)
80
+ rubocop
60
81
  rung!
82
+ yard
61
83
 
62
84
  BUNDLED WITH
63
85
  1.16.3
@@ -0,0 +1,111 @@
1
+ :!hardbreaks:
2
+ = Rung
3
+
4
+ image:https://circleci.com/gh/gogiel/rung/tree/master.svg?style=svg["CircleCI", link="https://circleci.com/gh/gogiel/rung/tree/master"]
5
+ https://codeclimate.com/github/gogiel/rung/maintainability[image:https://api.codeclimate.com/v1/badges/67ff3c0c392c368d0156/maintainability[Maintainability]]
6
+
7
+ Rung is service object/business operation/Railway DSL.
8
+
9
+ This is a lightweight, independent alternative to
10
+ http://trailblazer.to/gems/operation[Trailblazer Operation]
11
+ and
12
+ https://github.com/dry-rb/dry-transaction[dry-transaction].
13
+
14
+ == Installation
15
+
16
+ Add this line to your application’s Gemfile:
17
+
18
+ [source,ruby]
19
+ ----
20
+ gem 'rung'
21
+ ----
22
+
23
+ And then execute:
24
+
25
+ ....
26
+ $ bundle
27
+ ....
28
+
29
+ Or install it yourself as:
30
+
31
+ ....
32
+ $ gem install rung
33
+ ....
34
+
35
+ == Example Usage
36
+
37
+ Example:
38
+
39
+ [source,ruby]
40
+ ----
41
+ class CreateOrder < Rung::Operation
42
+ step do |state|
43
+ state[:order_id] = "order-#{SecureRandom.uuid }"
44
+ end
45
+ step ValidateMagazineState
46
+ step :log_start
47
+
48
+ step WithBenchmark do
49
+ step CreateTemporaryOrder
50
+ step :place_order
51
+ end
52
+
53
+ step :log_success
54
+ failure :log_failure
55
+
56
+ def log_start(state)
57
+ state[:logger].log("Creating order #{state[:order_id]}")
58
+ end
59
+
60
+ def log_success(state)
61
+ state[:logger].log("Order #{state[:order_id]} created successfully")
62
+ end
63
+
64
+ def log_failure(state)
65
+ state[:logger].log("Order #{state[:order_id]} not created")
66
+ end
67
+
68
+ def place_order(state)
69
+ status = OrdersRepository.create(state[:order_id])
70
+
71
+ # Step return value is important.
72
+ # If step returns falsy value then the operation is considered as a failure.
73
+ status == :success
74
+ end
75
+ end
76
+
77
+ result = CreateOrder.call(logger: Rails.logger)
78
+ if result.success?
79
+ print "Created order #{result[:order_id]}"
80
+ end
81
+ ----
82
+
83
+ == Docs
84
+
85
+ Docs are available at https://gogiel.github.io/rung/.
86
+
87
+ They are generated from Cucumber specifications using
88
+ https://github.com/rmpestano/cukedoctor[Cukedoctor].
89
+
90
+ Docs can be generated locally using `$ rake docker_generate_docs`. It requires Docker.
91
+
92
+ == Development
93
+
94
+ After checking out the repo, run `bundle` to install dependencies. Then,
95
+ run `rake` to run the tests. You can also run `bin/console` for an
96
+ interactive prompt that will allow you to experiment.
97
+
98
+ To install this gem onto your local machine, run
99
+ `bundle exec rake install`. To release a new version, update the version
100
+ number in `version.rb`, and then run `bundle exec rake release`, which
101
+ will create a git tag for the version, push git commits and tags, and
102
+ push the `.gem` file to https://rubygems.org[rubygems.org].
103
+
104
+ == Contributing
105
+
106
+ Bug reports and pull requests are welcome on GitHub at https://github.com/gogiel/rung.
107
+
108
+ == License
109
+
110
+ The gem is available as open source under the terms of the
111
+ https://opensource.org/licenses/MIT[MIT License].
data/Rakefile CHANGED
@@ -1,8 +1,23 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
3
- require "cucumber/rake/task"
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ require 'cucumber/rake/task'
4
+ require 'rubocop/rake_task'
4
5
 
5
6
  RSpec::Core::RakeTask.new(:spec)
7
+ RuboCop::RakeTask.new
6
8
  Cucumber::Rake::Task.new(:cucumber)
9
+ Cucumber::Rake::Task.new(
10
+ :cucumber_json, 'Generate Cucumber JSON in tmp/'
11
+ ) do |t|
12
+ t.cucumber_opts = %w[-f json -o tmp/cucumber.json]
13
+ end
7
14
 
8
- task :default => [:spec, :cucumber]
15
+ task default: %i[spec cucumber rubocop]
16
+
17
+ desc 'Generate Cukedoctor docs in generated_doc/ using docker'
18
+ task docker_generate_docs: [:cucumber_json] do
19
+ sh 'docker run -v "$PWD:/output" -w /output rmpestano/cukedoctor' \
20
+ ' -o generated_doc/index -f html5 -p tmp/cucumber.json' \
21
+ ' -t "Rung Documentation" -hideSummarySection -hideStepTime' \
22
+ ' -hideScenarioKeyword -hideFeaturesSection'
23
+ end
@@ -1,11 +1,34 @@
1
- Feature: steps_definition
2
- There are multiple ways of defining steps.
3
- Steps definition order is important as they are always executed in order.
1
+ # order: 10
2
+ Feature: Operation definition
3
+ :!hardbreaks:
4
+ Operation defines a business process that consists of multiple steps.
5
+
6
+ For example when in e-commerce application new order is created then
7
+ the system should update state of the warehouse, send an e-mail, create new waybill etc.
8
+
9
+ To define Operation create a new class based on `Rung::Operation`.
10
+ Inside it you can define steps using Rung DSL.
11
+ Steps definition order is important as they are always executed in order.
12
+
13
+ Steps can communicate with each other and the external world using State. When
14
+ operation is called then new state object is created.
15
+ State is shared between step executions and available as a result of operation.
16
+ See link:#State[State chapter] to learn more.
17
+
18
+ There are multiple ways of defining steps:
19
+
20
+ * using a block
21
+ * Symbol with a method name
22
+ * using object that responds to `.call`
23
+
24
+ Each method can be used with a an argument (state) or with no arguments.
25
+
26
+ TIP: Using block notation is not advised. It's made primarily for debugging.
4
27
 
5
28
  Scenario: Steps can be defined as a Ruby block
6
29
  Given definition
7
30
  """ruby
8
- class Operation < Rung::Base
31
+ class Operation < Rung::Operation
9
32
  step do |state|
10
33
  state[:what] = "World"
11
34
  end
@@ -35,7 +58,7 @@ Feature: steps_definition
35
58
  Scenario: Steps can be defined as methods
36
59
  Given definition
37
60
  """ruby
38
- class Operation < Rung::Base
61
+ class Operation < Rung::Operation
39
62
  step :set_what_state
40
63
  step :print_hello
41
64
  step "print_what"
@@ -94,7 +117,7 @@ Feature: steps_definition
94
117
 
95
118
  PrintBang = -> { print_to_output "!" }
96
119
 
97
- class Operation < Rung::Base
120
+ class Operation < Rung::Operation
98
121
  step SetWhatState.new("World")
99
122
  step PrintHello
100
123
  step PrintWhat
@@ -1,9 +1,18 @@
1
- Feature: state
1
+ # order: 20
2
+ Feature: State
3
+ :!hardbreaks:
4
+ State is a Hash object that is shared between step executions.
5
+
6
+ It's used to share state between steps and communicate with external world.
7
+
8
+ User can provide initial state when calling the operation. By default it's empty.
9
+
10
+ State can be used as the operation output as it is accessible in the result object.
2
11
 
3
12
  Scenario: State is shared across step executions
4
13
  Given definition
5
14
  """ruby
6
- class Operation < Rung::Base
15
+ class Operation < Rung::Operation
7
16
  step do |state|
8
17
  state[:what] = "World!"
9
18
  end
@@ -29,7 +38,7 @@ Feature: state
29
38
  Scenario: State is available in the result object
30
39
  Given definition
31
40
  """ruby
32
- class Operation < Rung::Base
41
+ class Operation < Rung::Operation
33
42
  step do |state|
34
43
  state[:output_text] = "Hello "
35
44
  end
@@ -51,7 +60,7 @@ Feature: state
51
60
  Scenario: Initial state can be passed to call method
52
61
  Given definition
53
62
  """ruby
54
- class Operation < Rung::Base
63
+ class Operation < Rung::Operation
55
64
  step do |state|
56
65
  state[:output_text] << "World!"
57
66
  end
@@ -65,3 +74,7 @@ Feature: state
65
74
  """
66
75
  @result[:output_text] == "Hello World!"
67
76
  """
77
+ And I can assure that
78
+ """
79
+ @result.to_h == { output_text: "Hello World!" }
80
+ """
@@ -1,11 +1,26 @@
1
- Feature: failure
2
- Operation call returns `Rung::Runner::Result` object that can be either a success or a failure.
3
- Result has `success?` and `failure?` methods.
1
+ # order: 30
2
+ Feature: Success and failure
3
+ :!hardbreaks:
4
+ Rung gem is based on
5
+ link:https://fsharpforfunandprofit.com/rop/[Railway oriented programming]
6
+ idea. If you are not familiar with this concept I highly recommend
7
+ watching link:https://vimeo.com/113707214[Scott Wlaschin's presentation] first.
8
+
9
+ Value returned from step call is important. Successful step should
10
+ return truthy value (anything other than `false` or `nil`).
11
+
12
+ If step returns falsy value (`false` or `nil`) then
13
+ the operation is marked as failed. All next steps are not executed.
14
+
15
+ Result of the Operation call (`Rung::State` object)
16
+ can be either a success or a failure.
17
+ It can be checked using `State` has `success?` and `fail?`
18
+ (with `failed?`, `failure?` aliases) methods.
4
19
 
5
20
  Scenario: When all steps return truthy value the result is a success
6
21
  Given definition
7
22
  """ruby
8
- class Operation < Rung::Base
23
+ class Operation < Rung::Operation
9
24
  step do
10
25
  # do something...
11
26
  true
@@ -30,11 +45,19 @@ Feature: failure
30
45
  """
31
46
  @result.failure? == false
32
47
  """
48
+ And I can assure that `fail?` alias works
49
+ """
50
+ @result.fail? == false
51
+ """
52
+ And I can assure that `failed?` alias works
53
+ """
54
+ @result.failed? == false
55
+ """
33
56
 
34
57
  Scenario: When at least one step returns a falsy value then the result is a failure
35
58
  Given definition
36
59
  """ruby
37
- class Operation < Rung::Base
60
+ class Operation < Rung::Operation
38
61
  step do
39
62
  # do something...
40
63
  true
@@ -63,7 +86,7 @@ Feature: failure
63
86
  Scenario: When a step fails then the next steps are not executed
64
87
  Given definition
65
88
  """ruby
66
- class Operation < Rung::Base
89
+ class Operation < Rung::Operation
67
90
  step do
68
91
  print_to_output "Hello"
69
92
  true