appkernel 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,4 +1,20 @@
1
- == 0.1.0 2009-06-29
1
+ == 0.1.3 YYY-MM-DD
2
+
3
+ * x major enhancements
4
+ * functions defined in the same scope can call themselves
5
+ * validations can call function in the same module
6
+ * ability to provide defaults for function arguments.
7
+ * allow multiple classes in the :type option attribute
8
+
9
+ == 0.1.2 2009-07-01
10
+
11
+ * 1 major enhancment:
12
+ * can't remember for the life of me what it was. Are you really reading this?
13
+
14
+ * 1 major enhancement:
15
+ * functioning prototype which allows you to create portable, self-validating functions
16
+
17
+ == 0.1.1 2009-06-30
2
18
 
3
19
  * 1 major enhancement:
4
20
  * functioning prototype which allows you to create portable, self-validating functions
data/Manifest.txt CHANGED
@@ -1,5 +1,6 @@
1
1
  History.txt
2
2
  Manifest.txt
3
+ PostInstall.txt
3
4
  README.rdoc
4
5
  Rakefile
5
6
  lib/appkernel.rb
@@ -12,4 +13,3 @@ spec/appkernel/function_spec.rb
12
13
  spec/appkernel/validation_spec.rb
13
14
  spec/spec.opts
14
15
  spec/spec_helper.rb
15
- tasks/rspec.rake
data/PostInstall.txt ADDED
@@ -0,0 +1,6 @@
1
+
2
+ This gem brought to you by The Frontside Software, Inc.
3
+ http://www.thefrontside.net
4
+
5
+
6
+
data/Rakefile CHANGED
@@ -1,29 +1,28 @@
1
- require 'rubygems' unless ENV['NO_RUBYGEMS']
2
- %w[rake rake/clean fileutils newgem rubigen].each { |f| require f }
3
- $:.unshift(File.dirname(__FILE__) + '/lib') unless $:.member?(File.dirname(__FILE__) + '/lib')
1
+ require 'rubygems'
2
+ gem 'hoe', '>= 2.1.0'
3
+ require 'hoe'
4
+ require 'fileutils'
5
+
6
+ $:.unshift File.dirname(__FILE__) + '/lib'
4
7
  require 'appkernel'
5
8
 
9
+ Hoe.plugin :newgem
10
+ # Hoe.plugin :website
11
+ # Hoe.plugin :cucumber_features
12
+
6
13
  # Generate all the Rake tasks
7
14
  # Run 'rake -T' to see list of generated tasks (from gem root directory)
8
- $hoe = Hoe.new('appkernel', AppKernel::VERSION) do |p|
9
- p.developer('Charles Lowell', 'cowboyd@thefrontside.net')
10
- p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
11
- p.rubyforge_name = p.name # TODO this is default value
12
- # p.extra_deps = [
13
- # ['activesupport','>= 2.0.2'],
14
- # ]
15
- p.extra_dev_deps = [
16
- ['newgem', ">= #{::Newgem::VERSION}"]
17
- ]
18
-
19
- p.clean_globs |= %w[**/.DS_Store tmp *.log]
20
- path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
21
- p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
22
- p.rsync_args = '-av --delete --ignore-errors'
15
+ $hoe = Hoe.spec 'appkernel' do
16
+ self.developer 'Charles Lowell', 'cowboyd@thefrontside.net'
17
+ self.post_install_message = 'PostInstall.txt' # TODO remove if post-install message not required
18
+ self.rubyforge_name = self.name # TODO this is default value
19
+ # self.extra_deps = [['activesupport','>= 2.0.2']]
20
+
23
21
  end
24
22
 
25
- require 'newgem/tasks' # load /tasks/*.rake
23
+ require 'newgem/tasks'
26
24
  Dir['tasks/**/*.rake'].each { |t| load t }
27
25
 
28
26
  # TODO - want other tests/tasks run by default? Add them to the list
27
+ # remove_task :default
29
28
  # task :default => [:spec, :features]
data/lib/appkernel.rb CHANGED
@@ -1,6 +1,6 @@
1
1
 
2
2
  class AppKernel
3
- VERSION = "0.1.1"
3
+ VERSION = "0.1.2"
4
4
  require 'appkernel/function'
5
5
  require 'appkernel/validation'
6
6
  end
@@ -10,7 +10,7 @@ class AppKernel
10
10
  def self.included(mod)
11
11
  class << mod
12
12
  def function(symbol, &definition)
13
- fun = ::AppKernel::FunctionDefinition.new(symbol, definition)
13
+ fun = ::AppKernel::FunctionDefinition.new(symbol, self, definition)
14
14
  self.const_set(symbol, fun)
15
15
  self.send(:define_method, symbol) do |*args|
16
16
  FunctionApplication.apply_or_die(fun, *args)
@@ -39,7 +39,7 @@ class AppKernel
39
39
  @function = fun
40
40
  @errors = {}
41
41
  @args = Arguments.new(self, *args)
42
- @return_value = self.class.do_apply(self, *args)
42
+ @return_value = self.class.do_apply(self)
43
43
  end
44
44
 
45
45
  def successful?
@@ -67,22 +67,36 @@ class AppKernel
67
67
  if opt = fun.options[k.to_sym]
68
68
  set opt, v
69
69
  else
70
- raise FunctionCallError, "unknown option :#{@name}"
70
+ raise FunctionCallError, "#{fun.name}: unknown option :#{k}"
71
71
  end
72
72
  end
73
73
  elsif opt = @optorder.shift
74
74
  set opt, arg
75
75
  end
76
76
  end
77
+ for opt in fun.options.values
78
+ if @canonical[opt.name].nil? && !opt.default.nil?
79
+ @canonical[opt.name] = opt.default
80
+ @required.delete opt
81
+ end
82
+ end
77
83
  for opt in @required
78
- app.errors[opt.name] = "missing required option '#{@name}'"
84
+ app.errors[opt.name] = "missing required option '#{opt.name}'"
79
85
  end
86
+ for name in fun.options.keys
87
+ @canonical[name] = nil if @canonical[name].nil?
88
+ end
80
89
  end
81
90
 
82
- def set(opt, value)
83
- if resolved = opt.resolve(@app, value)
91
+ def set(opt, value)
92
+ resolved = opt.resolve(@app, value)
93
+ if !resolved.nil?
84
94
  @canonical[opt.name] = resolved
85
95
  @required.delete opt
96
+ elsif !value.nil? && opt.required?
97
+ @required.delete opt
98
+ @required.delete opt
99
+ @app.errors[opt.name] = "no such value '#{value}' for required option '#{opt.name}'"
86
100
  end
87
101
  end
88
102
  end
@@ -98,11 +112,12 @@ class AppKernel
98
112
  end
99
113
  end
100
114
 
101
- def do_apply(app, *args)
115
+ def do_apply(app)
102
116
  fun = app.function
103
117
  app.errors.merge! fun.validation.validate(app.options) if app.successful?
104
118
  if app.successful?
105
119
  scope = Object.new
120
+ scope.extend fun.mod
106
121
  for k,v in app.options do
107
122
  scope.instance_variable_set("@#{k}", v)
108
123
  end
@@ -114,13 +129,14 @@ class AppKernel
114
129
 
115
130
  class FunctionDefinition
116
131
 
117
- attr_reader :impl, :options, :validation
132
+ attr_reader :name, :mod, :impl, :options, :validation
118
133
 
119
- def initialize(name, definition)
134
+ def initialize(name, mod, definition)
120
135
  @name = name
136
+ @mod = mod
121
137
  @options = {}
122
138
  @impl = lambda {}
123
- @validation = ::AppKernel::Validation::Validator.new
139
+ @validation = ::AppKernel::Validation::Validator.new(self)
124
140
  self.instance_eval &definition
125
141
  end
126
142
 
@@ -138,7 +154,7 @@ class AppKernel
138
154
  end
139
155
 
140
156
  def validate(&checks)
141
- @validation = AppKernel::Validation::Validator.new(&checks)
157
+ @validation = AppKernel::Validation::Validator.new(self, &checks)
142
158
  end
143
159
 
144
160
  def to_s
@@ -147,13 +163,25 @@ class AppKernel
147
163
 
148
164
  class Option
149
165
  ID = lambda {|o| o}
150
- attr_reader :name, :index
166
+ attr_reader :name, :index, :default
151
167
  def initialize(name, params)
152
168
  @name = name.to_sym
153
169
  @index = params[:index]
154
170
  @required = params[:required] == true
155
171
  @finder = params[:find]
156
- @type = params[:type]
172
+ @types = params[:type] ? [params[:type]].flatten : nil
173
+ @default = params[:default]
174
+ validate!
175
+ end
176
+
177
+ def validate!
178
+ if @default
179
+ if @types
180
+ raise OptionError, "#{@default} is not a kind of #{@types.join('|')}" unless @types.detect {|t| @default.kind_of?(t)}
181
+ elsif @required
182
+ Kernel.warn "option '#{@name}' unecessarily marked as required. It has a default value"
183
+ end
184
+ end
157
185
  end
158
186
 
159
187
  def required?
@@ -167,13 +195,13 @@ class AppKernel
167
195
  def resolve(app, value)
168
196
  if value.nil?
169
197
  nil
170
- elsif @type
171
- if value.is_a?(@type)
198
+ elsif @types
199
+ if @types.detect {|t| value.is_a?(t)}
172
200
  value
173
201
  elsif @finder
174
202
  lookup(app, value)
175
203
  else
176
- raise FunctionDefinitionError, "Don't know how to convert #{value.class}:#{value} -> #{@type}"
204
+ raise OptionError, "Don't know how to convert #{value.class}:#{value} -> #{@type}"
177
205
  end
178
206
  elsif @finder
179
207
  lookup(app, value)
@@ -186,8 +214,7 @@ class AppKernel
186
214
  result = @finder.call(value)
187
215
  app.errors[@name] = "couldn't find '#{@name}': #{value}" if result.nil?
188
216
  result
189
- end
190
-
217
+ end
191
218
  end
192
219
 
193
220
  class Validator
@@ -195,6 +222,7 @@ class AppKernel
195
222
  end
196
223
 
197
224
  class FunctionCallError < StandardError; end
225
+ class OptionError < StandardError; end
198
226
 
199
227
  class ValidationError < StandardError
200
228
  def initialize(application)
@@ -202,7 +230,7 @@ class AppKernel
202
230
  end
203
231
 
204
232
  def message
205
- @app.errors.values.first
233
+ "#{@app.function.name}: #{@app.errors.values.first}"
206
234
  end
207
235
  end
208
236
 
@@ -4,13 +4,15 @@ module AppKernel::Validation
4
4
 
5
5
  attr_reader :errors
6
6
 
7
- def initialize(&block)
7
+ def initialize(fun, &block)
8
+ @fun = fun
8
9
  @body = block
9
10
  end
10
11
 
11
12
  def validate(vars = {})
12
13
  errors = {}
13
14
  scope = Object.new
15
+ scope.extend @fun.mod
14
16
  for k,v in vars do
15
17
  val = case v
16
18
  when nil
@@ -19,6 +21,10 @@ module AppKernel::Validation
19
21
  FixnumValue.new(v)
20
22
  when Symbol
21
23
  v
24
+ when FalseClass
25
+ FalseValue.new
26
+ when TrueClass
27
+ TrueValue.new
22
28
  else
23
29
  v.dup
24
30
  end
@@ -56,6 +62,18 @@ module AppKernel::Validation
56
62
  end
57
63
  end
58
64
 
65
+ class FalseValue < DelegateClass(FalseClass)
66
+ def initialize
67
+ super(false)
68
+ end
69
+ end
70
+
71
+ class TrueValue < DelegateClass(TrueClass)
72
+ def initialize
73
+ super(true)
74
+ end
75
+ end
76
+
59
77
  class FixnumValue < DelegateClass(Fixnum)
60
78
  def initialize(val)
61
79
  super(val)
@@ -70,6 +70,22 @@ describe AppKernel::Function do
70
70
  end
71
71
  end
72
72
 
73
+ it "allows functions in the same module to be accessible without namespacing" do
74
+ function :First do
75
+ execute do
76
+ Second()
77
+ end
78
+ end
79
+
80
+ function :Second do
81
+ execute do
82
+ "Hello"
83
+ end
84
+ end
85
+
86
+ First().should == "Hello"
87
+ end
88
+
73
89
  it "can be called by using the apply method instead of invoking it directly" do
74
90
  function :FiveAlive do
75
91
  option :desc, :index => 1
@@ -139,13 +155,62 @@ describe AppKernel::Function do
139
155
  TakesInt("5").should == 5
140
156
  end
141
157
 
158
+ describe "Default Values" do
159
+ it "allows for any option to have a default value" do
160
+ function :HasDefault do
161
+ option :value, :default => 5
162
+
163
+ execute{@value}
164
+ end
165
+
166
+ HasDefault().should == 5
167
+ end
168
+
169
+ it "requires that the default value be the same as the option type if that is specified" do
170
+ lambda {
171
+ function :InvalidDefault do
172
+ option :value, :type => Integer, :default => "NOT_INT"
173
+ end
174
+ }.should raise_error
175
+ end
176
+
177
+ it "warns if an option has a default and is also required" do
178
+ Kernel.should_receive(:warn)
179
+ function :QuestionableDefault do
180
+ option :value, :required => true, :default => 5
181
+ end
182
+ end
183
+
184
+ it "sets a default option even if that option is explicitly passed in as nil" do
185
+ function :ExplicitNil do
186
+ option :value, :default => 'fun'
187
+ execute{@value}
188
+ end
189
+
190
+ ExplicitNil(:value => nil).should == 'fun'
191
+ end
192
+ end
193
+
142
194
  it "doesn't do an argument conversion if the argument is already of the correct type" do
143
195
  function :TakesInt do
144
196
  option :num, :index => 1, :type => Integer, :find => proc {|s| raise StandardError, "Hey, don't call me!"}
145
197
  execute {@num}
146
198
  end
147
-
148
- TakesInt(5).should == 5
199
+ lambda {
200
+ TakesInt(5).should == 5
201
+ }.should_not raise_error
202
+ end
203
+
204
+ it "an option can have multiple valid types" do
205
+ function :MultipleValidOptionTypes do
206
+ option :bool, :index => 1, :type => [TrueClass, FalseClass], :find => proc {|s| s == "true"}
207
+ execute {@bool}
208
+ end
209
+
210
+ MultipleValidOptionTypes("true").should be(true)
211
+ MultipleValidOptionTypes("false").should be(false)
212
+ MultipleValidOptionTypes(true).should be(true)
213
+ MultipleValidOptionTypes(false).should be(false)
149
214
  end
150
215
 
151
216
  it "raises an exception if it can't tell how to find a complex type" do
@@ -185,6 +250,16 @@ describe AppKernel::Function do
185
250
  Noop(:foo => 'bar')
186
251
  }.should raise_error(AppKernel::FunctionCallError)
187
252
  end
253
+
254
+ it "allows false as a default value" do
255
+ function :FalseDefault do
256
+ option :bool, :default => false
257
+ execute {@bool}
258
+ end
259
+
260
+ FalseDefault().should be(false)
261
+ end
262
+
188
263
  end
189
264
 
190
265
  def function(sym, &body)
@@ -25,7 +25,7 @@ describe AppKernel::Validation do
25
25
  end
26
26
 
27
27
  def validate(vars = {}, &block)
28
- v = AppKernel::Validation::Validator.new(&block)
28
+ v = AppKernel::Validation::Validator.new(stub(:Fun, :mod => Module.new),&block)
29
29
  v.validate vars
30
30
  end
31
31
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appkernel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Charles Lowell
@@ -9,19 +9,9 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-06-29 00:00:00 -05:00
12
+ date: 2009-11-13 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
- - !ruby/object:Gem::Dependency
16
- name: newgem
17
- type: :development
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
20
- requirements:
21
- - - ">="
22
- - !ruby/object:Gem::Version
23
- version: 1.4.1
24
- version:
25
15
  - !ruby/object:Gem::Dependency
26
16
  name: hoe
27
17
  type: :development
@@ -30,7 +20,7 @@ dependencies:
30
20
  requirements:
31
21
  - - ">="
32
22
  - !ruby/object:Gem::Version
33
- version: 1.8.0
23
+ version: 2.3.3
34
24
  version:
35
25
  description: |-
36
26
  AppKernel is a microframework for capturing your application in terms of minute, self-validating functions.
@@ -44,10 +34,11 @@ extensions: []
44
34
  extra_rdoc_files:
45
35
  - History.txt
46
36
  - Manifest.txt
47
- - README.rdoc
37
+ - PostInstall.txt
48
38
  files:
49
39
  - History.txt
50
40
  - Manifest.txt
41
+ - PostInstall.txt
51
42
  - README.rdoc
52
43
  - Rakefile
53
44
  - lib/appkernel.rb
@@ -60,12 +51,11 @@ files:
60
51
  - spec/appkernel/validation_spec.rb
61
52
  - spec/spec.opts
62
53
  - spec/spec_helper.rb
63
- - tasks/rspec.rake
64
54
  has_rdoc: true
65
55
  homepage: http://github.com/cowboyd/appkernel
66
56
  licenses: []
67
57
 
68
- post_install_message:
58
+ post_install_message: PostInstall.txt
69
59
  rdoc_options:
70
60
  - --main
71
61
  - README.rdoc
@@ -86,7 +76,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
86
76
  requirements: []
87
77
 
88
78
  rubyforge_project: appkernel
89
- rubygems_version: 1.3.4
79
+ rubygems_version: 1.3.5
90
80
  signing_key:
91
81
  specification_version: 3
92
82
  summary: AppKernel is a microframework for capturing your application in terms of minute, self-validating functions
data/tasks/rspec.rake DELETED
@@ -1,21 +0,0 @@
1
- begin
2
- require 'spec'
3
- rescue LoadError
4
- require 'rubygems' unless ENV['NO_RUBYGEMS']
5
- require 'spec'
6
- end
7
- begin
8
- require 'spec/rake/spectask'
9
- rescue LoadError
10
- puts <<-EOS
11
- To use rspec for testing you must install rspec gem:
12
- gem install rspec
13
- EOS
14
- exit(0)
15
- end
16
-
17
- desc "Run the specs under spec/models"
18
- Spec::Rake::SpecTask.new do |t|
19
- t.spec_opts = ['--options', "spec/spec.opts"]
20
- t.spec_files = FileList['spec/**/*_spec.rb']
21
- end