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
@@ -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
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
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: 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 -05:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activerecord
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description:
26
+ email: patnakajima@gmail.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files: []
32
+
33
+ files:
34
+ - lib/core_ext
35
+ - lib/core_ext/hash.rb
36
+ - lib/fixjour
37
+ - lib/fixjour/builders.rb
38
+ - lib/fixjour/errors.rb
39
+ - lib/fixjour/verify.rb
40
+ - lib/fixjour.rb
41
+ has_rdoc: true
42
+ homepage: http://github.com/nakajima/fixjour
43
+ post_install_message:
44
+ rdoc_options: []
45
+
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: "0"
53
+ version:
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: "0"
59
+ version:
60
+ requirements: []
61
+
62
+ rubyforge_project:
63
+ rubygems_version: 1.3.1
64
+ signing_key:
65
+ specification_version: 2
66
+ summary: Object creation methods everyone already has
67
+ test_files: []
68
+