rung 0.0.1.pre.alpha → 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 (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