nakajima-fixjour 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.
@@ -0,0 +1,9 @@
1
+ class Hash
2
+ # Makes a hash able to be accessed via symbol or string keys.
3
+ def make_indifferent!
4
+ keys_values = self.dup
5
+ indifferent = Hash.new { |h,k| h[k.to_s] if Symbol === k }
6
+ replace(indifferent)
7
+ merge!(keys_values)
8
+ end
9
+ end
data/lib/fixjour.rb ADDED
@@ -0,0 +1,14 @@
1
+ $LOAD_PATH << File.dirname(__FILE__)
2
+
3
+ require 'rubygems'
4
+ require 'activerecord'
5
+ require 'core_ext/hash'
6
+ require 'fixjour/verify'
7
+ require 'fixjour/errors'
8
+ require 'fixjour/builders'
9
+
10
+ # This method is just for prettiness
11
+ def Fixjour(&block)
12
+ return Fixjour unless block_given?
13
+ Fixjour.module_eval(&block)
14
+ end
@@ -0,0 +1,68 @@
1
+ module Fixjour
2
+ class << self
3
+ # The list of classes that have builders defined.
4
+ def builders
5
+ @builders ||= Set.new
6
+ end
7
+
8
+ # Registers a class' builder. This allows us to make sure
9
+ # redundant builders aren't defined, which can lead to confusion
10
+ # when trying to figure out where objects are being created.
11
+ def add_builder(klass)
12
+ unless builders.add?(klass)
13
+ raise RedundantBuilder.new("You already defined a builder for #{klass.inspect}")
14
+ end
15
+ end
16
+
17
+ # This method should always return a valid instance of
18
+ # a model object.
19
+ def define_builder(klass, &block)
20
+ add_builder(klass)
21
+
22
+ name = name_for(klass)
23
+
24
+ define_new(name, block)
25
+ define_create(name)
26
+ define_valid_attributes(name)
27
+ end
28
+
29
+ private
30
+
31
+ def name_for(klass)
32
+ klass.model_name.singular
33
+ end
34
+
35
+ # Defines the new_* method
36
+ def define_new(name, block)
37
+ define_method("new_#{name}") do |*args|
38
+ overrides = args.first || { }
39
+ block.bind(self).call(overrides)
40
+ end
41
+ end
42
+
43
+ # Defines the create_* method
44
+ def define_create(name)
45
+ define_method("create_#{name}") do |*args|
46
+ model = send("new_#{name}", *args)
47
+ model.save!
48
+ model
49
+ end
50
+ end
51
+
52
+ # Defines the valid_*_attributes method
53
+ def define_valid_attributes(name)
54
+ define_method("valid_#{name}_attributes") do |*args|
55
+ if instance_variable_get("@__valid_#{name}_attrs").nil?
56
+ valid_attributes = send("new_#{name}").attributes
57
+ valid_attributes.delete_if { |key, value| value.nil? }
58
+ instance_variable_set("@__valid_#{name}_attrs", valid_attributes)
59
+ end
60
+
61
+ overrides = args.extract_options!
62
+ attrs = instance_variable_get("@__valid_#{name}_attrs").merge(overrides)
63
+ attrs.make_indifferent!
64
+ attrs
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,14 @@
1
+ module Fixjour
2
+ # Raised when a builder returns an invalid object
3
+ class InvalidBuilder < StandardError; end
4
+
5
+ # Raised when a builder returns an object of the wrong type
6
+ class WrongBuilderType < StandardError; end
7
+
8
+ # Raised when a builder is defined for a class that already
9
+ # has one.
10
+ class RedundantBuilder < StandardError; end
11
+
12
+ # Raised when a builder block saves the object.
13
+ class BuilderSavedRecord < StandardError; end
14
+ end
@@ -0,0 +1,36 @@
1
+ module Fixjour
2
+ class << self
3
+ # Checks each builder to ensure that they:
4
+ #
5
+ # * Return valid objects
6
+ # * The new_* methods return new records
7
+ # * The creation methods return objects of the proper type
8
+ def verify!
9
+ builders.each do |klass|
10
+ result = validity_checker.send("new_#{name_for(klass)}")
11
+
12
+ unless result.valid?
13
+ raise InvalidBuilder.new("The builder for #{klass} returns an invalid object")
14
+ end
15
+
16
+ unless result.new_record?
17
+ raise BuilderSavedRecord.new("The builder for #{klass} must not save the object")
18
+ end
19
+
20
+ unless result.is_a?(klass)
21
+ raise WrongBuilderType.new("The builder for #{klass} must return instance of #{klass}")
22
+ end
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def validity_checker
29
+ @evaluator ||= begin
30
+ klass = Class.new
31
+ klass.send :include, self
32
+ klass.new
33
+ end
34
+ end
35
+ end
36
+ end
metadata ADDED
@@ -0,0 +1,67 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nakajima-fixjour
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Pat Nakajima
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-12-29 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activerecord
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: "0"
23
+ version:
24
+ description:
25
+ email: patnakajima@gmail.com
26
+ executables: []
27
+
28
+ extensions: []
29
+
30
+ extra_rdoc_files: []
31
+
32
+ files:
33
+ - lib/core_ext
34
+ - lib/core_ext/hash.rb
35
+ - lib/fixjour
36
+ - lib/fixjour/builders.rb
37
+ - lib/fixjour/errors.rb
38
+ - lib/fixjour/verify.rb
39
+ - lib/fixjour.rb
40
+ has_rdoc: true
41
+ homepage: http://github.com/nakajima/fixjour
42
+ post_install_message:
43
+ rdoc_options: []
44
+
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: "0"
52
+ version:
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ version:
59
+ requirements: []
60
+
61
+ rubyforge_project:
62
+ rubygems_version: 1.2.0
63
+ signing_key:
64
+ specification_version: 2
65
+ summary: Object creation methods everyone already has
66
+ test_files: []
67
+