obvious 0.0.0 → 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.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in obvious.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Brian Knapp
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Obvious
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'obvious'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install obvious
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/obvious ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'obvious'
4
+
5
+ if ARGV[0] == 'generate'
6
+ Obvious::generate
7
+ end
@@ -0,0 +1,4 @@
1
+ task :rspec do
2
+ sh 'rspec ./app -c'
3
+ end
4
+
@@ -0,0 +1,135 @@
1
+ class Contract
2
+ @@disable_override = false
3
+
4
+ # This method needs to exist because the method_added bit looks for it.
5
+ # It intentionally returns an empty array
6
+ def self.contracts
7
+ []
8
+ end
9
+
10
+ # This method will move methods defined in self.contracts into new methods.
11
+ # Each entry in self.contracts will cause the method with the same name to
12
+ # become method_name_alias and for the original method to point to
13
+ # method_name_contract.
14
+ def self.method_added name
15
+ unless @@disable_override
16
+ self.contracts.each do |method|
17
+ if name == method.to_sym
18
+ method_alias = "#{method}_alias".to_sym
19
+ method_contract = "#{method}_contract".to_sym
20
+
21
+ @@disable_override = true # to stop the new build method
22
+ self.send :alias_method, method_alias, name
23
+ self.send :remove_method, name
24
+ self.send :alias_method, name, method_contract
25
+
26
+ @@disable_override = false
27
+ else
28
+ # puts self.inspect
29
+ # puts "defining other method #{name}"
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ # This method is used as a shorthand to mak the contract method calling pattern more DRY
36
+ # It starts by checking if you are sending in input and if so will check the input shape for
37
+ # errors. If no errors are found it calls the method via the passed in symbol(method).
38
+ #
39
+ # Output checking is more complicated because of the types of output we check for. Nil is
40
+ # never valid output. If we pass in the output shape of true, that means we are looking for
41
+ # result to be the object True. If the output shape is an array, that is actually a shorthand
42
+ # for telling our output check to look at the output as an array and compare it to the shape
43
+ # stored in output_shape[0]. If we pass in the symbol :true_false it means we are looking for
44
+ # the result to be either true or false. The default case will just check if result has the shape
45
+ # of the output_shape.
46
+ def call_method method, input, input_shape, output_shape
47
+ if input != nil && input_shape != nil
48
+ unless input.has_shape? input_shape
49
+ raise ContractInputError, 'incorrect input data format'
50
+ end
51
+
52
+ result = self.send method, input
53
+ else
54
+ result = self.send method
55
+ end
56
+
57
+ # check output
58
+ # output should never be nil
59
+ if result == nil
60
+ raise ContractOutputError, 'incorrect output data format'
61
+ end
62
+
63
+ # we are looking for result to be a True object
64
+ if output_shape === true
65
+ if output_shape == result
66
+ return result
67
+ else
68
+ raise ContractOutputError, 'incorrect output data format'
69
+ end
70
+ end
71
+
72
+ # we want to check the shape of each item in the result array
73
+ if output_shape.class == Array
74
+ if result.class == Array
75
+ inner_shape = output_shape[0]
76
+ result.each do |item|
77
+ unless item.has_shape? inner_shape
78
+ raise ContractOutputError, 'incorrect output data format'
79
+ end
80
+ end
81
+
82
+ return result
83
+ end
84
+ raise ContractOutputError, 'incorrect output data format'
85
+ end
86
+
87
+ # we want result to be true or false
88
+ if output_shape == :true_false
89
+ unless result == true || result == false
90
+ raise ContractOutputError, 'incorrect output data format'
91
+ end
92
+
93
+ return result
94
+ end
95
+
96
+ # we want result to be output_shape's shape
97
+ unless result.has_shape? output_shape
98
+ raise ContractOutputError, 'incorrect output data format'
99
+ end
100
+
101
+ result
102
+ end
103
+
104
+ end
105
+
106
+ # via https://github.com/citizen428/shenanigans/blob/master/lib/shenanigans/hash/has_shape_pred.rb
107
+ class Hash
108
+ # Checks if a hash has a certain structure.
109
+ # h = { k1: 1, k2: "1" }
110
+ # h.has_shape?(k1: Fixnum, k2: String)
111
+ # #=> true
112
+ # h.has_shape?(k1: Class, k2: String)
113
+ # #=> false
114
+ # It also works with compound data structures.
115
+ # h = { k1: [], k2: { k3: Struct.new("Foo") } }
116
+ # shape = { k1: Array, k2: { k3: Module } }
117
+ # h.has_shape?(shape)
118
+ # #=> true
119
+ def has_shape?(shape)
120
+ # I added an empty check
121
+ if self.empty?
122
+ return shape.empty?
123
+ end
124
+
125
+ all? do |k, v|
126
+ Hash === v ? v.has_shape?(shape[k]) : shape[k] === v
127
+ end
128
+ end
129
+ end
130
+
131
+ class ContractInputError < StandardError
132
+ end
133
+
134
+ class ContractOutputError < StandardError
135
+ end
@@ -0,0 +1,3 @@
1
+ module Obvious
2
+ VERSION = "0.0.1"
3
+ end
data/lib/obvious.rb CHANGED
@@ -1,5 +1,284 @@
1
- class Obvious
2
- def self.hi
3
- puts "Hello world!"
1
+ require "obvious/version"
2
+ require 'yaml'
3
+
4
+ module Obvious
5
+ # Your code goes here...
6
+ def self.generate
7
+ puts 'generate the codes!a'
8
+
9
+
10
+
11
+ #`rm -rf app`
12
+
13
+ app_dir = 'app'
14
+
15
+ counter = 1
16
+ while File.directory? app_dir
17
+ app_dir = "app_#{counter}"
18
+ counter += 1
19
+ end
20
+
21
+ puts "Generating application at: #{app_dir}"
22
+
23
+ dirs = ['/', '/actions', '/contracts', '/entities',
24
+ '/spec', '/spec/actions', '/spec/contracts', '/spec/entities',
25
+ '/spec/doubles']
26
+
27
+ dirs.each do |dir|
28
+ Dir.mkdir app_dir + dir
29
+ end
30
+
31
+
32
+ target_path = File.realpath Dir.pwd
33
+ spec = Gem::Specification.find_by_name("obvious")
34
+ gem_root = spec.gem_dir
35
+ gem_lib = gem_root + "/lib"
36
+
37
+ `cp #{gem_lib}/obvious/files/contract.rb #{target_path}/app/contracts/contract.rb`
38
+ `cp #{gem_lib}/obvious/files/Rakefile #{target_path}/Rakefile`
39
+ entities = Hash.new
40
+ jacks = Hash.new
41
+
42
+ files = Dir['descriptors/*.yml']
43
+
44
+ files.each do |file|
45
+ action = YAML.load_file file
46
+ code = ''
47
+ #puts action.inspect
48
+
49
+ local_jacks = Hash.new
50
+ local_entities = Hash.new
51
+
52
+ action['Code'].each do |entry|
53
+ code << " \# #{entry['c']}\n"
54
+ code << " \# use: #{entry['requires']}\n" if entry['requires']
55
+ code << " \n"
56
+
57
+ if entry['requires']
58
+ requires = entry['requires'].split(',')
59
+ requires.each do |req|
60
+ req.strip!
61
+ info = req.split '.'
62
+
63
+ if info[0].index 'Jack'
64
+ unless jacks[info[0]]
65
+ jacks[info[0]] = []
66
+ end
67
+
68
+ unless local_jacks[info[0]]
69
+ local_jacks[info[0]] = []
70
+ end
71
+
72
+ jacks[info[0]] << info[1]
73
+ local_jacks[info[0]] << info[1]
74
+ else
75
+ unless entities[info[0]]
76
+ entities[info[0]] = []
77
+ end
78
+
79
+ unless local_entities[info[0]]
80
+ local_entities[info[0]] = []
81
+ end
82
+
83
+ entities[info[0]] << info[1]
84
+ local_entities[info[0]] << info[1]
85
+ end
86
+
87
+ end
88
+ end
89
+
90
+ end
91
+
92
+
93
+ jack_inputs = ''
94
+ jack_assignments = ''
95
+
96
+ local_jacks.each do |k, v|
97
+ name = k.chomp('Jack').downcase
98
+ jack_inputs << "#{name}_jack, "
99
+ jack_assignments << " @#{name}_jack = #{name}_jack\n"
100
+ end
101
+
102
+ jack_inputs.chomp! ', '
103
+
104
+ entity_requires = ''
105
+
106
+ local_entities.each do |k, v|
107
+ name = k.downcase
108
+ entity_requires << "require_relative '../entities/#{name}'\n"
109
+ end
110
+
111
+
112
+ output = <<FIN
113
+ #{entity_requires}
114
+ class #{action['Action']}
115
+
116
+ def initialize #{jack_inputs}
117
+ #{jack_assignments} end
118
+
119
+ def do input
120
+ #{code} end
121
+
122
+ end
123
+ FIN
124
+ snake_name = action['Action'].gsub(/(.)([A-Z])/,'\1_\2').downcase
125
+
126
+ filename = "app/actions/#{snake_name}.rb"
127
+ File.open(filename, 'w') {|f| f.write(output) }
128
+
129
+ #puts output
130
+
131
+ output = <<FIN
132
+ require_relative '../../actions/#{snake_name}'
133
+
134
+ describe #{action['Action']} do
135
+
136
+ it '#{action['Description']}'
137
+
138
+ it 'should raise an error with invalid input'
139
+
140
+ end
141
+
142
+
143
+ FIN
144
+
145
+ filename = "app/spec/actions/#{snake_name}_spec.rb"
146
+ File.open(filename, 'w') {|f| f.write(output) }
147
+
148
+ #puts output
149
+ end
150
+
151
+
152
+ #filter out duplicate methods
153
+
154
+ entities.each do |k, v|
155
+ v.uniq!
156
+ end
157
+
158
+ jacks.each do |k,v|
159
+ v.uniq!
160
+ end
161
+
162
+ #puts entities.inspect
163
+ #puts jacks.inspect
164
+
165
+ entities.each do |k, v|
166
+ name = k
167
+ method_specs = ''
168
+ method_definitions = ''
169
+
170
+ v.each do |method|
171
+ method_definitions << "
172
+ def #{method} input
173
+ nil
174
+ end
175
+ "
176
+
177
+ method_specs << "
178
+ describe '.#{method}' do
179
+ it 'should #{method} with valid input'
180
+
181
+ it 'should raise an error with invalid input'
182
+
183
+ end
184
+ "
185
+
186
+ end
187
+
188
+ output = <<FIN
189
+ class #{name}
190
+ #{method_definitions}
191
+ end
192
+ FIN
193
+ snake_name = name.gsub(/(.)([A-Z])/,'\1_\2').downcase
194
+
195
+ filename = "app/entities/#{snake_name}.rb"
196
+ File.open(filename, 'w') {|f| f.write(output) }
197
+
198
+ output = <<FIN
199
+ require_relative '../../entities/#{snake_name}'
200
+
201
+ describe #{name} do
202
+ #{method_specs}
203
+ end
204
+
205
+
206
+ FIN
207
+ filename = "app/spec/entities/#{snake_name}_spec.rb"
208
+ File.open(filename, 'w') {|f| f.write(output) }
209
+
210
+
211
+ #puts output
212
+ end
213
+
214
+
215
+
216
+ jacks.each do |k, v|
217
+
218
+ name = k.chomp('Jack').downcase
219
+
220
+ method_specs = ''
221
+ method_definitions = ''
222
+
223
+ v.each do |method|
224
+
225
+ method_definitions << "
226
+ def #{method}_contract input
227
+ input_shape = {}
228
+ output_shape = {}
229
+ call_method :#{method}_alias, input, input_shape, output_shape
230
+ end
231
+ "
232
+
233
+ method_specs << "
234
+ describe '.#{method}_contract' do
235
+ it 'should #{method} data with valid input'
236
+
237
+ it 'should raise an error with invalid input'
238
+
239
+ it 'should raise an error with invalid output'
240
+
241
+ end
242
+ "
243
+
244
+ end
245
+
246
+
247
+ output = <<FIN
248
+ require_relative 'contract'
249
+
250
+ class #{k}Contract < Contract
251
+ def self.contracts
252
+ #{v.to_s}
253
+ end
254
+ #{method_definitions}
255
+ end
256
+ FIN
257
+
258
+ snake_name = name.gsub(/(.)([A-Z])/,'\1_\2').downcase
259
+
260
+ filename = "app/contracts/#{snake_name}_contract.rb"
261
+ File.open(filename, 'w') {|f| f.write(output) }
262
+
263
+ #puts output
264
+
265
+ output = <<FIN
266
+ require_relative '../../contracts/#{snake_name}_contract'
267
+
268
+ describe #{k}Contract do
269
+ #{method_specs}
270
+ end
271
+
272
+ FIN
273
+
274
+ filename = "app/spec/contracts/#{snake_name}_spec.rb"
275
+ File.open(filename, 'w') {|f| f.write(output) }
276
+
277
+ #puts output
278
+ end
279
+
280
+
281
+
282
+
4
283
  end
5
284
  end
data/obvious.gemspec ADDED
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'obvious/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "obvious"
8
+ gem.version = Obvious::VERSION
9
+ gem.authors = ["Brian Knapp"]
10
+ gem.email = ["brianknapp@gmail.com"]
11
+ gem.description = "A set of tools to build apps using the Obvious Architecture"
12
+ gem.summary = "Isn't it Obvious?"
13
+ gem.homepage = ""
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ #gem.executables << 'obvious'
18
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
+ gem.require_paths = ["lib"]
20
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: obvious
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 0.0.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,16 +9,28 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-04 00:00:00.000000000 Z
12
+ date: 2012-12-22 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: A set of tools to build apps using the Obvious Architecture
15
- email: brian@programminggeek.com
16
- executables: []
15
+ email:
16
+ - brianknapp@gmail.com
17
+ executables:
18
+ - obvious
17
19
  extensions: []
18
20
  extra_rdoc_files: []
19
21
  files:
22
+ - .gitignore
23
+ - Gemfile
24
+ - LICENSE.txt
25
+ - README.md
26
+ - Rakefile
27
+ - bin/obvious
20
28
  - lib/obvious.rb
21
- homepage: http://rubygems.org/gems/obvious
29
+ - lib/obvious/files/Rakefile
30
+ - lib/obvious/files/contract.rb
31
+ - lib/obvious/version.rb
32
+ - obvious.gemspec
33
+ homepage: ''
22
34
  licenses: []
23
35
  post_install_message:
24
36
  rdoc_options: []
@@ -38,8 +50,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
38
50
  version: '0'
39
51
  requirements: []
40
52
  rubyforge_project:
41
- rubygems_version: 1.8.24
53
+ rubygems_version: 1.8.17
42
54
  signing_key:
43
55
  specification_version: 3
44
- summary: Obvious architecture toolset
56
+ summary: Isn't it Obvious?
45
57
  test_files: []
58
+ has_rdoc: