obvious 0.0.8 → 0.2.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.
@@ -0,0 +1,76 @@
1
+ require 'minitest/autorun'
2
+ require_relative '../lib/obvious/entity'
3
+
4
+ class Thing < Obvious::Entity
5
+ value :id, Integer
6
+ value :name, String
7
+ end
8
+
9
+ class Thing2 < Obvious::Entity
10
+ value :foo , String
11
+
12
+ validation :something, -> {
13
+ if foo != "hello world"
14
+ msg = "Validation Error: Invalid value for foo, should be 'hello world'"
15
+ raise Obvious::ValidationError.new msg
16
+ end
17
+ }
18
+
19
+ def modify_foo
20
+ @values[:foo] = 100
21
+ end
22
+ end
23
+
24
+ class Thing3 < Obvious::Entity
25
+ value :foo , String
26
+
27
+ validation :something, -> {
28
+ @values[:foo] = 12
29
+ }
30
+ end
31
+
32
+
33
+ # Test code begins here
34
+
35
+ class EntityTest < Minitest::Test
36
+ def test_valid_input
37
+ t = Thing.new(name: 'Thing', id: 1)
38
+ assert_equal('Thing', t.name)
39
+ assert_equal(1, t.id)
40
+ end
41
+
42
+ def test_invalid_input_types
43
+ assert_raises Obvious::TypeError do
44
+ Thing.new(name: nil, id: nil)
45
+ end
46
+ end
47
+
48
+ def test_invalid_extra_field
49
+ assert_raises Obvious::ShapeError do
50
+ Thing.new(name: 'Thing', id: 1, extra: 'should explode')
51
+ end
52
+ end
53
+
54
+ def test_method_modify_value
55
+ assert_raises RuntimeError do
56
+ Thing2.new(foo: 'hello world').modify_foo
57
+ end
58
+ end
59
+
60
+ def test_to_hash
61
+ t = Thing.new(name: 'Thing', id: 1)
62
+ assert_equal({name: 'Thing', id: 1}, t.to_hash)
63
+ end
64
+
65
+ def test_failed_validation
66
+ assert_raises Obvious::ValidationError do
67
+ Thing2.new(foo: 'not valid I promise!')
68
+ end
69
+ end
70
+
71
+ def test_modify_value_inside_validation
72
+ assert_raises RuntimeError do
73
+ Thing3.new(foo: 'hello world')
74
+ end
75
+ end
76
+ end
data/test/obj_test.rb ADDED
@@ -0,0 +1,65 @@
1
+ require 'minitest/autorun'
2
+ require_relative '../lib/obvious/obj'
3
+
4
+ class TestObj
5
+ include Obvious::Obj
6
+
7
+ def initialize
8
+ @local = 'set!'
9
+ end
10
+
11
+ define :defined_method, foo: String, bar: Integer do |input|
12
+ input
13
+ end
14
+
15
+ define :defined_local do |input|
16
+ @local
17
+ end
18
+
19
+ define :early_return_example do |input|
20
+ next true
21
+ false
22
+ end
23
+ end
24
+
25
+ class ObjTest < Minitest::Test
26
+ def test_valid_input
27
+ result = TestObj.new.defined_method foo: 'hello', bar: 12
28
+ assert_equal({foo: 'hello', bar: 12}, result)
29
+ end
30
+
31
+ def test_access_instance_variables
32
+ result = TestObj.new.defined_local
33
+ assert_equal('set!', result)
34
+ end
35
+
36
+ def test_missing_parameters
37
+ error = assert_raises ArgumentError do
38
+ TestObj.new.defined_method foo: 'hello'
39
+ end
40
+ assert_equal('missing input field bar', error.message)
41
+ end
42
+
43
+ def test_extra_parameters
44
+ error = assert_raises ArgumentError do
45
+ TestObj.new.defined_method foo: 'hello', bar: 12, extra: 'fail'
46
+ end
47
+ assert_equal('invalid input field extra', error.message)
48
+ end
49
+
50
+ def test_invalid_types
51
+ error = assert_raises ArgumentError do
52
+ TestObj.new.defined_method foo: 1, bar: 12
53
+ end
54
+ assert_equal('invalid type for foo expected String', error.message)
55
+
56
+ error = assert_raises ArgumentError do
57
+ TestObj.new.defined_method foo: 'hello', bar: nil
58
+ end
59
+ assert_equal('invalid type for bar expected Integer', error.message)
60
+ end
61
+
62
+ def test_early_return
63
+ assert(TestObj.new.early_return_example)
64
+ end
65
+ end
metadata CHANGED
@@ -1,87 +1,65 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: obvious
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
5
- prerelease:
4
+ version: 0.2.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Brian Knapp
8
+ - Shawn Baden
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-03-30 00:00:00.000000000 Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
15
- name: rspec
16
- requirement: &70341046505020 !ruby/object:Gem::Requirement
17
- none: false
18
- requirements:
19
- - - ! '>='
20
- - !ruby/object:Gem::Version
21
- version: '0'
22
- type: :development
23
- prerelease: false
24
- version_requirements: *70341046505020
12
+ date: 2022-02-02 00:00:00.000000000 Z
13
+ dependencies: []
25
14
  description: A set of tools to build apps using the Obvious Architecture
26
15
  email:
27
16
  - brianknapp@gmail.com
28
- executables:
29
- - obvious
17
+ - shawnbaden@hotmail.com
18
+ executables: []
30
19
  extensions: []
31
20
  extra_rdoc_files: []
32
21
  files:
33
- - .gitignore
22
+ - ".github/workflows/obvious.yml"
23
+ - ".gitignore"
24
+ - CHANGELOG.md
34
25
  - Gemfile
26
+ - Gemfile.lock
35
27
  - LICENSE.txt
36
28
  - README.md
37
29
  - Rakefile
38
- - bin/obvious
39
- - lib/generators/application_generator.rb
40
- - lib/generators/descriptor.rb
41
- - lib/generators/helpers/application.rb
42
30
  - lib/obvious.rb
43
31
  - lib/obvious/contract.rb
44
32
  - lib/obvious/entity.rb
45
- - lib/obvious/files/Rakefile
46
- - lib/obvious/files/external/fs_plug.rb
47
- - lib/obvious/files/external/mongo_plug.rb
48
- - lib/obvious/files/external/mysql_plug.rb
49
- - lib/obvious/files/external/s3_plug.rb
33
+ - lib/obvious/obj.rb
50
34
  - lib/obvious/version.rb
51
35
  - obvious.gemspec
52
- - spec/.spec_helper.rb.swp
53
- - spec/contract_spec.rb
54
- - spec/entity_spec.rb
55
- - spec/generators/descriptor_spec.rb
56
- - spec/spec_helper.rb
57
- homepage: http://obvious.retromocha.com/
58
- licenses: []
36
+ - test/contract_test.rb
37
+ - test/entity_test.rb
38
+ - test/obj_test.rb
39
+ homepage: https://github.com/RetroMocha/obvious
40
+ licenses:
41
+ - MIT
42
+ metadata: {}
59
43
  post_install_message:
60
44
  rdoc_options: []
61
45
  require_paths:
62
46
  - lib
63
47
  required_ruby_version: !ruby/object:Gem::Requirement
64
- none: false
65
48
  requirements:
66
- - - ! '>='
49
+ - - ">="
67
50
  - !ruby/object:Gem::Version
68
51
  version: '0'
69
52
  required_rubygems_version: !ruby/object:Gem::Requirement
70
- none: false
71
53
  requirements:
72
- - - ! '>='
54
+ - - ">="
73
55
  - !ruby/object:Gem::Version
74
56
  version: '0'
75
57
  requirements: []
76
- rubyforge_project:
77
- rubygems_version: 1.8.17
58
+ rubygems_version: 3.0.3
78
59
  signing_key:
79
- specification_version: 3
80
- summary: Isn't it Obvious?
60
+ specification_version: 4
61
+ summary: Clean Architecture framework
81
62
  test_files:
82
- - spec/.spec_helper.rb.swp
83
- - spec/contract_spec.rb
84
- - spec/entity_spec.rb
85
- - spec/generators/descriptor_spec.rb
86
- - spec/spec_helper.rb
87
- has_rdoc:
63
+ - test/contract_test.rb
64
+ - test/entity_test.rb
65
+ - test/obj_test.rb
data/bin/obvious DELETED
@@ -1,7 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'obvious'
4
-
5
- if ARGV[0] == 'generate'
6
- Obvious::Generators::ApplicationGenerator.generate
7
- end
@@ -1,199 +0,0 @@
1
- require 'yaml'
2
-
3
- require_relative 'helpers/application'
4
- require_relative 'descriptor'
5
-
6
- module Obvious
7
- module Generators
8
- class ApplicationGenerator
9
- class << self
10
- def generate
11
- @app = Obvious::Generators::Application.instance
12
-
13
- puts 'Generating the files...'
14
-
15
- Obvious::Generators::ApplicationGenerator.create_directories ['/', '/actions', '/contracts', '/entities',
16
- '/spec', '/spec/actions', '/spec/contracts', '/spec/entities',
17
- '/spec/doubles']
18
-
19
- unless File.exist? "#{@app.target_path}/Rakefile"
20
- puts 'Creating Rakefile...'
21
- `cp #{@app.lib_path}/obvious/files/Rakefile #{@app.target_path}/Rakefile`
22
- end
23
-
24
- unless File.exist? "#{@app.target_path}/external"
25
- puts 'Creating external directory'
26
- `cp -r #{@app.lib_path}/obvious/files/external #{@app.target_path}/external`
27
- end
28
-
29
- descriptors = Dir['descriptors/*.yml']
30
-
31
- puts 'Creating actions from descriptors... ' unless descriptors.length.zero?
32
- descriptors.each do |file|
33
- yaml = YAML.load_file(file)
34
- descriptor = Obvious::Generators::Descriptor.new yaml
35
- descriptor.to_file
36
- end
37
-
38
- @app.remove_duplicates
39
-
40
- puts 'Writing Entities scaffolds... '
41
- Obvious::Generators::ApplicationGenerator.write_entities
42
-
43
- puts 'Writing jacks scaffolds... '
44
- Obvious::Generators::ApplicationGenerator.write_jacks
45
-
46
- puts "Files are located in the `#{@app.dir}` directory."
47
- end # ::generate
48
-
49
- def create_directories directories
50
- directories.each do |dir|
51
- Dir.mkdir @app.dir + dir
52
- end
53
- end
54
-
55
- def write_entities
56
- @app.entities.each do |k, v|
57
- name = k
58
- method_specs = ''
59
- method_defs = ''
60
-
61
- method_defs << '
62
- def self.shape
63
- {}
64
- end
65
- '
66
-
67
- v.each do |method|
68
- method_defs << "
69
- def #{method} input
70
- nil
71
- end
72
- "
73
-
74
- method_specs << "
75
- describe '.#{method}' do
76
- it 'should #{method} with valid input'
77
-
78
- it 'should raise an error with invalid input'
79
-
80
- end
81
- "
82
- end
83
-
84
- output = %Q{class #{name}
85
- #{method_defs}
86
- end
87
- }
88
- snake_name = name.gsub(/(.)([A-Z])/,'\1_\2').downcase
89
-
90
- filename = "#{@app.dir}/entities/#{snake_name}.rb"
91
- File.open(filename, 'w') { |f| f.write(output) }
92
-
93
- output = %Q{require_relative '../../entities/#{snake_name}'
94
-
95
- describe #{name} do
96
- #{method_specs}
97
- end
98
- }
99
-
100
- filename = "#{@app.dir}/spec/entities/#{snake_name}_spec.rb"
101
- File.open(filename, 'w') {|f| f.write(output) }
102
- end
103
- end #write_entities
104
-
105
- def write_jacks
106
- @app.jacks.each do |k, v|
107
- name = k.chomp('Jack').downcase
108
- method_specs = ''
109
- contract_defs = ''
110
-
111
- jack_double_default_methods = ''
112
- jack_double_badoutput_methods = ''
113
-
114
- v.each do |method|
115
-
116
- contract_defs << "
117
- contract_for :#{method}, {
118
- :input => {},
119
- :output => {},
120
- }
121
- "
122
-
123
- method_specs << "
124
- describe '.#{method}_contract' do
125
- it 'should #{method} data with valid input'
126
-
127
- it 'should raise an error with invalid input'
128
-
129
- it 'should raise an error with invalid output'
130
-
131
- end
132
- "
133
-
134
- jack_double_default_methods << "
135
- def #{method} input
136
- {}
137
- end
138
- "
139
-
140
- jack_double_badoutput_methods << "
141
- def #{method} input
142
- nil
143
- end
144
- "
145
- end
146
-
147
- output = %Q{require 'obvious'
148
-
149
- class #{k}Contract < Contract
150
- #{contract_defs}
151
- end
152
- }
153
-
154
- snake_name = k.gsub(/(.)([A-Z])/,'\1_\2').downcase
155
-
156
- filename = "#{@app.dir}/contracts/#{snake_name}_contract.rb"
157
- File.open(filename, 'w') {|f| f.write(output) }
158
-
159
- output = %Q{require_relative '../../contracts/#{snake_name}_contract'
160
-
161
- describe #{k}Contract do
162
- #{method_specs}
163
- end
164
- }
165
-
166
- filename = "#{@app.dir}/spec/contracts/#{snake_name}_spec.rb"
167
- File.open(filename, 'w') {|f| f.write(output) }
168
-
169
- output = %Q{require_relative '../../contracts/#{snake_name}_contract'
170
-
171
- class #{k}Double
172
- def self.create behavior
173
- case behavior
174
- when :bad_output
175
- #{k}_BadOutput.new
176
- when :default
177
- #{k}_Default.new
178
- end
179
- end
180
- end
181
-
182
- class #{k}_Default < #{k}Contract
183
- #{jack_double_default_methods}
184
- end
185
-
186
- class #{k}_BadOutput < #{k}Contract
187
- #{jack_double_badoutput_methods}
188
- end
189
- }
190
-
191
- filename = "#{@app.dir}/spec/doubles/#{snake_name}_double.rb"
192
- File.open(filename, 'w') {|f| f.write(output) }
193
-
194
- end
195
- end # generate_jacks_code
196
- end
197
- end
198
- end
199
- end
@@ -1,131 +0,0 @@
1
- require 'yaml'
2
-
3
- require_relative 'helpers/application'
4
-
5
- module Obvious
6
- module Generators
7
- class InvalidDescriptorError < StandardError; end
8
-
9
- class Descriptor
10
- def initialize descriptor
11
- @descriptor = descriptor
12
- end
13
-
14
- def to_file
15
- validate_descriptor
16
-
17
- @jacks, @entities = {}, {}
18
- @code = ''
19
-
20
- @descriptor['Code'].each do |entry|
21
- write_comments_for entry
22
- process_requirements_for entry if entry['requires']
23
- end
24
-
25
- write_action
26
- end
27
-
28
- private
29
- def write_comments_for entry
30
- @code << " \# #{entry['c']}\n"
31
- @code << " \# use: #{entry['requires']}\n" if entry['requires']
32
- @code << " \n"
33
- end
34
-
35
- def process_requirements_for entry
36
- app = Obvious::Generators::Application.instance
37
- requires = entry['requires'].split ','
38
-
39
- requires.each do |req|
40
- req.strip!
41
- infos = req.split '.'
42
-
43
- if infos[0].index 'Jack'
44
- app.jacks[infos[0]] = [] unless app.jacks[infos[0]]
45
- @jacks[infos[0]] = [] unless @jacks[infos[0]]
46
-
47
- app.jacks[infos[0]] << infos[1]
48
- @jacks[infos[0]] << infos[1]
49
- else
50
- app.entities[infos[0]] = [] unless app.entities[infos[0]]
51
- @entities[infos[0]] = [] unless @entities[infos[0]]
52
-
53
- app.entities[infos[0]] << infos[1]
54
- @entities[infos[0]] << infos[1]
55
- end
56
- end
57
- end # #process_requirements_for
58
-
59
- def write_action
60
- jacks_data = process_jacks
61
- requirements = require_entities
62
-
63
- output = %Q{#{requirements}
64
- class #{@descriptor['Action']}
65
-
66
- def initialize #{jacks_data[:inputs]}
67
- #{jacks_data[:assignments]} end
68
-
69
- def execute input
70
- #{@code} end
71
- end
72
- }
73
-
74
- snake_name = @descriptor['Action'].gsub(/(.)([A-Z])/,'\1_\2').downcase
75
-
76
- filename = "#{Obvious::Generators::Application.instance.dir}/actions/#{snake_name}.rb"
77
- File.open(filename, 'w') {|f| f.write(output) }
78
-
79
- output = %Q{require_relative '../../actions/#{snake_name}'
80
-
81
- describe #{@descriptor['Action']} do
82
-
83
- it '#{@descriptor['Description']}'
84
-
85
- it 'should raise an error with invalid input'
86
-
87
- end
88
- }
89
-
90
- filename = "#{Obvious::Generators::Application.instance.dir}/spec/actions/#{snake_name}_spec.rb"
91
- File.open(filename, 'w') {|f| f.write(output) }
92
- end
93
-
94
- def process_jacks
95
- jack_inputs = ''
96
- jack_assignments = ''
97
-
98
- @jacks.each do |k, v|
99
- name = k.chomp('Jack').downcase
100
- jack_inputs << "#{name}_jack, "
101
- jack_assignments << " @#{name}_jack = #{name}_jack\n"
102
- end
103
-
104
- jack_inputs.chomp! ', '
105
-
106
- {
107
- inputs: jack_inputs,
108
- assignments: jack_assignments
109
- }
110
- end
111
-
112
- def require_entities
113
- entity_requires = ''
114
-
115
- @entities.each do |k, v|
116
- snake_name = k.gsub(/(.)([A-Z])/,'\1_\2').downcase
117
- entity_requires << "require_relative '../entities/#{snake_name}'\n"
118
- end
119
-
120
- entity_requires
121
- end
122
-
123
- def validate_descriptor
124
- raise InvalidDescriptorError unless @descriptor
125
- raise InvalidDescriptorError if @descriptor['Code'].nil?
126
- raise InvalidDescriptorError if @descriptor['Action'].nil?
127
- raise InvalidDescriptorError if @descriptor['Description'].nil?
128
- end
129
- end # ::Descriptor
130
- end
131
- end
@@ -1,47 +0,0 @@
1
- require 'singleton'
2
-
3
- module Obvious
4
- module Generators
5
- class Application
6
- include Singleton
7
-
8
- attr_reader :jacks, :entities, :dir
9
-
10
- def initialize
11
- @dir = 'app'
12
-
13
- counter = 1
14
- while File.directory? @dir
15
- @dir = "app_#{counter}"
16
- counter += 1
17
- end
18
- end
19
-
20
- def jacks
21
- @jacks ||= {}
22
- end
23
-
24
- def entities
25
- @entities ||= {}
26
- end
27
-
28
- def target_path
29
- File.realpath Dir.pwd
30
- end
31
-
32
- def lib_path
33
- Gem::Specification.find_by_name("obvious").gem_dir + '/lib'
34
- end
35
-
36
- def remove_duplicates
37
- entities.each do |k, v|
38
- v.uniq!
39
- end
40
-
41
- jacks.each do |k,v|
42
- v.uniq!
43
- end
44
- end
45
- end # ::Application
46
- end
47
- end
@@ -1,4 +0,0 @@
1
- task :rspec do
2
- sh 'rspec ./app -c'
3
- end
4
-