id 0.0.12 → 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.
- checksums.yaml +4 -4
- data/Gemfile +0 -3
- data/Gemfile.lock +25 -10
- data/LICENSE.md +1 -1
- data/README.md +173 -35
- data/id.gemspec +8 -3
- data/lib/id.rb +21 -15
- data/lib/id/active_model.rb +30 -0
- data/lib/id/association.rb +26 -0
- data/lib/id/boolean.rb +8 -0
- data/lib/id/coercion.rb +38 -0
- data/lib/id/eta_expansion.rb +5 -0
- data/lib/id/field.rb +46 -0
- data/lib/id/field/definition.rb +44 -0
- data/lib/id/field/summary.rb +35 -0
- data/lib/id/form.rb +41 -13
- data/lib/id/form_backwards_compatibility.rb +6 -0
- data/lib/id/hashifier.rb +13 -24
- data/lib/id/model.rb +29 -25
- data/lib/id/timestamps.rb +15 -15
- data/lib/id/validations.rb +8 -0
- data/spec/examples/cat_spec.rb +37 -0
- data/spec/lib/id/active_model_spec.rb +40 -0
- data/spec/lib/id/association_spec.rb +73 -0
- data/spec/lib/id/boolean_spec.rb +38 -0
- data/spec/lib/id/coercion_spec.rb +53 -0
- data/spec/lib/id/eta_expansion_spec.rb +13 -0
- data/spec/lib/id/field/definition_spec.rb +37 -0
- data/spec/lib/id/field/summary_spec.rb +26 -0
- data/spec/lib/id/field_spec.rb +62 -0
- data/spec/lib/id/form_spec.rb +84 -0
- data/spec/lib/id/hashifier_spec.rb +19 -0
- data/spec/lib/id/model_spec.rb +30 -180
- data/spec/lib/id/timestamps_spec.rb +22 -20
- data/spec/lib/id/validations_spec.rb +18 -0
- data/spec/spec_helper.rb +11 -5
- data/spec/support/dummy_rails_form_builder.rb +9 -0
- metadata +84 -26
- data/lib/id/form/active_model_form.rb +0 -41
- data/lib/id/form/descriptor.rb +0 -27
- data/lib/id/form/field_form.rb +0 -14
- data/lib/id/form/field_with_form_support.rb +0 -12
- data/lib/id/missing_attribute_error.rb +0 -4
- data/lib/id/model/association.rb +0 -49
- data/lib/id/model/definer.rb +0 -23
- data/lib/id/model/descriptor.rb +0 -23
- data/lib/id/model/field.rb +0 -61
- data/lib/id/model/has_many.rb +0 -11
- data/lib/id/model/has_one.rb +0 -17
- data/lib/id/model/type_casts.rb +0 -96
- data/spec/lib/id/model/association_spec.rb +0 -27
- data/spec/lib/id/model/field_spec.rb +0 -0
- data/spec/lib/id/model/form_spec.rb +0 -56
- data/spec/lib/id/model/type_casts_spec.rb +0 -44
- data/spec/lib/mike_spec.rb +0 -20
@@ -1,41 +0,0 @@
|
|
1
|
-
module Id
|
2
|
-
module Form
|
3
|
-
class ActiveModelForm
|
4
|
-
include ActiveModel::Validations
|
5
|
-
include ActiveModel::Conversion
|
6
|
-
extend ActiveModel::Naming
|
7
|
-
|
8
|
-
def self.i18n_scope
|
9
|
-
:id
|
10
|
-
end
|
11
|
-
|
12
|
-
def initialize(model)
|
13
|
-
@model = model
|
14
|
-
end
|
15
|
-
|
16
|
-
def persisted?
|
17
|
-
false
|
18
|
-
end
|
19
|
-
|
20
|
-
def to_model
|
21
|
-
self
|
22
|
-
end
|
23
|
-
|
24
|
-
def to_partial_path
|
25
|
-
model.respond_to?(:to_partial_path) ? model.to_partial_path : super
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
def method_missing(name, *args, &block)
|
31
|
-
model.send(name, *args, &block)
|
32
|
-
end
|
33
|
-
|
34
|
-
def memoize(f, &b)
|
35
|
-
instance_variable_get("@#{f}") || instance_variable_set("@#{f}", b.call)
|
36
|
-
end
|
37
|
-
|
38
|
-
attr_reader :model
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
data/lib/id/form/descriptor.rb
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
module Id
|
2
|
-
module Form
|
3
|
-
module Descriptor
|
4
|
-
|
5
|
-
def field(f, options={})
|
6
|
-
FieldWithFormSupport.new(self, f, options).define
|
7
|
-
end
|
8
|
-
|
9
|
-
def form &block
|
10
|
-
form_object.send :instance_exec, &block
|
11
|
-
end
|
12
|
-
|
13
|
-
def form_object
|
14
|
-
base = self
|
15
|
-
@form_object ||= Class.new(ActiveModelForm) do
|
16
|
-
eingenclass = class << self
|
17
|
-
self
|
18
|
-
end
|
19
|
-
eingenclass.send(:define_method, :model_name) do
|
20
|
-
ActiveModel::Name.new(self, nil, base.name)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
data/lib/id/form/field_form.rb
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
class FieldForm
|
2
|
-
|
3
|
-
def self.define(field)
|
4
|
-
field.model.form_object.instance_eval do
|
5
|
-
define_method field.name do
|
6
|
-
memoize field.name do
|
7
|
-
Option[model.send(field.name)].flatten.value_or nil if model.data.has_key? field.key
|
8
|
-
end
|
9
|
-
end
|
10
|
-
attr_writer field.name
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
end
|
data/lib/id/model/association.rb
DELETED
@@ -1,49 +0,0 @@
|
|
1
|
-
module Id
|
2
|
-
module Model
|
3
|
-
class Association < Field
|
4
|
-
|
5
|
-
def type
|
6
|
-
options.fetch(:type) { inferred_class }
|
7
|
-
end
|
8
|
-
|
9
|
-
def inferred_class
|
10
|
-
hierarchy.parent.const_get(inferred_class_name)
|
11
|
-
end
|
12
|
-
|
13
|
-
def inferred_class_name
|
14
|
-
@inferred_class_name ||= name.to_s.classify
|
15
|
-
end
|
16
|
-
|
17
|
-
def hierarchy
|
18
|
-
@hierarchy ||= Hierarchy.new(model.name, inferred_class_name)
|
19
|
-
end
|
20
|
-
|
21
|
-
class Hierarchy
|
22
|
-
|
23
|
-
def initialize(path, child)
|
24
|
-
@path = path
|
25
|
-
@child = child
|
26
|
-
end
|
27
|
-
|
28
|
-
def parent
|
29
|
-
@parent ||= constants.find do |c|
|
30
|
-
c.ancestors.find { |anc| anc.const_defined? child }
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def constants
|
35
|
-
hierarchy.map(&:constantize)
|
36
|
-
end
|
37
|
-
|
38
|
-
private
|
39
|
-
|
40
|
-
def hierarchy(name=path)
|
41
|
-
name.match /(.*)::.*$/
|
42
|
-
$1 ? [name] + hierarchy($1) : [name]
|
43
|
-
end
|
44
|
-
|
45
|
-
attr_reader :path, :child
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
data/lib/id/model/definer.rb
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
module Id
|
2
|
-
module Model
|
3
|
-
class Definer
|
4
|
-
|
5
|
-
def self.method_memoize(context, name, &value_block)
|
6
|
-
method(context, name) do |object|
|
7
|
-
object.instance_eval do
|
8
|
-
memoize(name, &value_block)
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
def self.method(context, name, &value_block)
|
14
|
-
context.instance_eval do
|
15
|
-
define_method name do
|
16
|
-
value_block.call(self)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
data/lib/id/model/descriptor.rb
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
module Id
|
2
|
-
module Model
|
3
|
-
module Descriptor
|
4
|
-
|
5
|
-
def field(f, options={})
|
6
|
-
Field.new(self, f, options).define
|
7
|
-
end
|
8
|
-
|
9
|
-
def has_one(f, options={})
|
10
|
-
HasOne.new(self, f, options).define
|
11
|
-
end
|
12
|
-
|
13
|
-
def has_many(f, options={})
|
14
|
-
HasMany.new(self, f, options).define
|
15
|
-
end
|
16
|
-
|
17
|
-
def to_proc
|
18
|
-
lambda { |data| new data }
|
19
|
-
end
|
20
|
-
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
data/lib/id/model/field.rb
DELETED
@@ -1,61 +0,0 @@
|
|
1
|
-
module Id
|
2
|
-
module Model
|
3
|
-
class Field
|
4
|
-
|
5
|
-
def initialize(model, name, options)
|
6
|
-
@model = model
|
7
|
-
@name = name
|
8
|
-
@options = options
|
9
|
-
end
|
10
|
-
|
11
|
-
def define
|
12
|
-
Definer.method_memoize(model, name) { |data| value_of(data) }
|
13
|
-
Definer.method(model, "#{name}?") { |obj| presence_of(obj.data) }
|
14
|
-
hook_define
|
15
|
-
end
|
16
|
-
|
17
|
-
def hook_define
|
18
|
-
end
|
19
|
-
|
20
|
-
def value_of(data)
|
21
|
-
value = data.fetch(key, &default_value)
|
22
|
-
optional ? Option[value].map{ |d| cast d } : cast(value)
|
23
|
-
end
|
24
|
-
|
25
|
-
def presence_of(data)
|
26
|
-
data.has_key?(key) && data.fetch(key)
|
27
|
-
end
|
28
|
-
|
29
|
-
def cast(value)
|
30
|
-
TypeCasts.cast(options.fetch(:type, false), value)
|
31
|
-
end
|
32
|
-
|
33
|
-
def key
|
34
|
-
options.fetch(:key, name).to_s
|
35
|
-
end
|
36
|
-
|
37
|
-
def default_value
|
38
|
-
proc do
|
39
|
-
if default? then default
|
40
|
-
elsif !optional? then raise MissingAttributeError, key end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def default?
|
45
|
-
options.has_key?(:default)
|
46
|
-
end
|
47
|
-
|
48
|
-
def default
|
49
|
-
options.fetch(:default)
|
50
|
-
end
|
51
|
-
|
52
|
-
def optional?
|
53
|
-
options.fetch(:optional, false)
|
54
|
-
end
|
55
|
-
alias_method :optional, :optional?
|
56
|
-
|
57
|
-
attr_reader :model, :name, :options
|
58
|
-
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
data/lib/id/model/has_many.rb
DELETED
data/lib/id/model/has_one.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
module Id
|
2
|
-
module Model
|
3
|
-
class HasOne < Association
|
4
|
-
|
5
|
-
def value_of(data)
|
6
|
-
if optional?
|
7
|
-
child = data.fetch(key, nil)
|
8
|
-
child.nil? ? None : Some[type.new(child)]
|
9
|
-
else
|
10
|
-
child = data.fetch(key) { raise MissingAttributeError, key }
|
11
|
-
type.new(child) unless child.nil?
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
data/lib/id/model/type_casts.rb
DELETED
@@ -1,96 +0,0 @@
|
|
1
|
-
module Id
|
2
|
-
module Model
|
3
|
-
module TypeCasts
|
4
|
-
|
5
|
-
def self.cast(type, value)
|
6
|
-
casts.fetch(type, Identity).new(value).cast
|
7
|
-
end
|
8
|
-
|
9
|
-
protected
|
10
|
-
|
11
|
-
def self.register(cast)
|
12
|
-
casts[cast.type] = cast
|
13
|
-
end
|
14
|
-
|
15
|
-
private
|
16
|
-
|
17
|
-
def self.casts
|
18
|
-
@casts ||= {}
|
19
|
-
end
|
20
|
-
|
21
|
-
class Cast
|
22
|
-
|
23
|
-
def initialize(value)
|
24
|
-
@value = value
|
25
|
-
end
|
26
|
-
|
27
|
-
def cast
|
28
|
-
value.is_a?(type) ? value : conversion
|
29
|
-
end
|
30
|
-
|
31
|
-
def type
|
32
|
-
self.class.type
|
33
|
-
end
|
34
|
-
|
35
|
-
def conversion
|
36
|
-
raise NotImplementedError
|
37
|
-
end
|
38
|
-
|
39
|
-
private
|
40
|
-
|
41
|
-
def self.type
|
42
|
-
raise NotImplementedError
|
43
|
-
end
|
44
|
-
|
45
|
-
attr_reader :value
|
46
|
-
|
47
|
-
end
|
48
|
-
|
49
|
-
class Identity < Cast
|
50
|
-
def cast
|
51
|
-
value
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
class Date < Cast
|
56
|
-
|
57
|
-
def self.type
|
58
|
-
::Date
|
59
|
-
end
|
60
|
-
|
61
|
-
def conversion
|
62
|
-
::Date.parse value
|
63
|
-
end
|
64
|
-
|
65
|
-
TypeCasts.register(self)
|
66
|
-
end
|
67
|
-
|
68
|
-
class Time < Cast
|
69
|
-
|
70
|
-
def self.type
|
71
|
-
::Time
|
72
|
-
end
|
73
|
-
|
74
|
-
def conversion
|
75
|
-
::Time.parse value
|
76
|
-
end
|
77
|
-
|
78
|
-
TypeCasts.register(self)
|
79
|
-
end
|
80
|
-
|
81
|
-
class Money < Cast
|
82
|
-
|
83
|
-
def self.type
|
84
|
-
::Money
|
85
|
-
end
|
86
|
-
|
87
|
-
def conversion
|
88
|
-
::Money.new value.to_i
|
89
|
-
end
|
90
|
-
|
91
|
-
TypeCasts.register(self)
|
92
|
-
end
|
93
|
-
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Id::Model::Association do
|
4
|
-
|
5
|
-
module Foo
|
6
|
-
module Bar
|
7
|
-
module Baz
|
8
|
-
class Quux
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
let (:model) { stub(:name => "Foo::Bar::Baz::Quux") }
|
15
|
-
let (:has_one) { Id::Model::Association.new(model, "yak", {}) }
|
16
|
-
|
17
|
-
describe "hierarchy" do
|
18
|
-
it "builds the class and module hierarchy for the model" do
|
19
|
-
has_one.hierarchy.constants.should eq [
|
20
|
-
Foo::Bar::Baz::Quux,
|
21
|
-
Foo::Bar::Baz,
|
22
|
-
Foo::Bar,
|
23
|
-
Foo
|
24
|
-
]
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
File without changes
|
@@ -1,56 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
class Gerbil
|
4
|
-
include Id::Model
|
5
|
-
include Id::Form
|
6
|
-
|
7
|
-
field :name
|
8
|
-
field :paws
|
9
|
-
|
10
|
-
form do
|
11
|
-
validates_presence_of :name
|
12
|
-
validates_length_of :name, :maximum => 4
|
13
|
-
end
|
14
|
-
|
15
|
-
def name_in_caps
|
16
|
-
name.upcase
|
17
|
-
end
|
18
|
-
|
19
|
-
end
|
20
|
-
|
21
|
-
module Id
|
22
|
-
module Model
|
23
|
-
describe Form do
|
24
|
-
|
25
|
-
let (:gerbil) { Gerbil.new(:name => 'Berty') }
|
26
|
-
let (:form) { gerbil.as_form }
|
27
|
-
|
28
|
-
subject { gerbil.as_form }
|
29
|
-
|
30
|
-
it_behaves_like "ActiveModel"
|
31
|
-
|
32
|
-
it 'is delegated to by the model for errors' do
|
33
|
-
gerbil.errors.should eq form.errors
|
34
|
-
gerbil.valid?.should eq form.valid?
|
35
|
-
end
|
36
|
-
|
37
|
-
it 'responds to to_model' do
|
38
|
-
subject.to_model.should eq subject
|
39
|
-
end
|
40
|
-
|
41
|
-
it 'has the same fields as the model' do
|
42
|
-
form.name.should eq 'Berty'
|
43
|
-
end
|
44
|
-
|
45
|
-
it 'works with active model validations' do
|
46
|
-
form.should_not be_valid
|
47
|
-
form.name = 'Bert'
|
48
|
-
form.should be_valid
|
49
|
-
end
|
50
|
-
|
51
|
-
it 'delegates to the model' do
|
52
|
-
form.name_in_caps.should eq 'BERTY'
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|