obvious 0.0.0 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: