cistern 0.0.3 → 0.1.2

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.
data/.gitignore CHANGED
@@ -15,3 +15,4 @@ spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
+ .rspec
data/Gemfile CHANGED
@@ -2,3 +2,16 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in cistern.gemspec
4
4
  gemspec
5
+
6
+ group :test do
7
+ gem "rspec", "~> 2.0"
8
+ gem "guard-rspec"
9
+ gem "rake"
10
+ gem 'rb-fsevent', '~> 0.9.1'
11
+ end
12
+
13
+ group :formatters do
14
+ gem 'formatador'
15
+ gem 'awesome_print'
16
+ end
17
+
data/Guardfile ADDED
@@ -0,0 +1,6 @@
1
+ guard 'rspec' do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { "spec" }
4
+ watch('spec/spec_helper.rb') { "spec" }
5
+ end
6
+
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Cistern
2
2
 
3
+ [![Build Status](https://secure.travis-ci.org/lanej/cistern.png)](http://travis-ci.org/lanej/cistern)
4
+
3
5
  TODO: Write a gem description
4
6
 
5
7
  ## Installation
@@ -20,10 +22,14 @@ Or install it yourself as:
20
22
 
21
23
  TODO: Write usage instructions here
22
24
 
25
+ ## Releasing
26
+
27
+ $ gem bump -trv (major|minor|patch)
28
+
23
29
  ## Contributing
24
30
 
25
31
  1. Fork it
26
32
  2. Create your feature branch (`git checkout -b my-new-feature`)
27
33
  3. Commit your changes (`git commit -am 'Added some feature'`)
28
34
  4. Push to the branch (`git push origin my-new-feature`)
29
- 5. Create new Pull Request
35
+ . Create new Pull Request
data/Rakefile CHANGED
@@ -1,2 +1,5 @@
1
1
  #!/usr/bin/env rake
2
- require "bundler/gem_tasks"
2
+ require 'bundler/gem_tasks'
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:default)
data/cistern.gemspec CHANGED
@@ -6,7 +6,7 @@ Gem::Specification.new do |gem|
6
6
  gem.email = ["me@joshualane.com"]
7
7
  gem.description = %q{API client framework extracted from Fog}
8
8
  gem.summary = %q{API client framework}
9
- gem.homepage = ""
9
+ gem.homepage = "http://joshualane.com/cistern"
10
10
 
11
11
  gem.files = `git ls-files`.split($\)
12
12
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
@@ -14,6 +14,4 @@ Gem::Specification.new do |gem|
14
14
  gem.name = "cistern"
15
15
  gem.require_paths = ["lib"]
16
16
  gem.version = Cistern::VERSION
17
-
18
- gem.add_dependency "formatador"
19
17
  end
@@ -1,203 +1,173 @@
1
- module Cistern
2
- module Attributes
3
- module ClassMethods
4
-
5
- def _load(marshalled)
6
- new(Marshal.load(marshalled))
7
- end
8
-
9
- def aliases
10
- @aliases ||= {}
11
- end
12
-
13
- def attributes
14
- @attributes ||= []
15
- end
1
+ module Cistern::Attributes
2
+ def self.parsers
3
+ @parsers ||= {
4
+ :string => lambda{|v,opts| v.to_s},
5
+ :time => lambda{|v,opts| v.is_a?(Time) ? v : v && Time.parse(v.to_s)},
6
+ :integer => lambda{|v,opts| v && v.to_i},
7
+ :float => lambda{|v,opts| v && v.to_f},
8
+ :array => lambda{|v,opts| [*v]},
9
+ :boolean => Proc.new do |v, opts|
10
+ {
11
+ true => true,
12
+ "true" => true,
13
+ "1" => true,
14
+ 1 => true,
15
+ false => false,
16
+ "false" => false,
17
+ "0" => false,
18
+ 0 => false,
19
+ }[v]
20
+ end,
21
+ }
22
+ end
16
23
 
17
- def attribute(name, options = {})
18
- class_eval <<-EOS, __FILE__, __LINE__
19
- def #{name}
20
- attributes[:#{name}]
21
- end
22
- EOS
23
- case options[:type]
24
- when :boolean
25
- class_eval <<-EOS, __FILE__, __LINE__
26
- def #{name}=(new_#{name})
27
- attributes[:#{name}] = case new_#{name}
28
- when true,'true'
29
- true
30
- when false,'false'
31
- false
32
- end
33
- end
34
- EOS
35
- when :float
36
- class_eval <<-EOS, __FILE__, __LINE__
37
- def #{name}=(new_#{name})
38
- attributes[:#{name}] = new_#{name} && new_#{name}.to_f
39
- end
40
- EOS
41
- when :integer
42
- class_eval <<-EOS, __FILE__, __LINE__
43
- def #{name}=(new_#{name})
44
- attributes[:#{name}] = new_#{name} && new_#{name}.to_i
45
- end
46
- EOS
47
- when :string
48
- class_eval <<-EOS, __FILE__, __LINE__
49
- def #{name}=(new_#{name})
50
- attributes[:#{name}] = new_#{name} && new_#{name}.to_s
51
- end
52
- EOS
53
- when :time
54
- class_eval <<-EOS, __FILE__, __LINE__
55
- def #{name}=(new_#{name})
56
- attributes[:#{name}] = if new_#{name}.nil? || new_#{name} == "" || new_#{name}.is_a?(Time)
57
- new_#{name}
58
- else
59
- Time.parse(new_#{name})
60
- end
61
- end
62
- EOS
63
- when :array
64
- class_eval <<-EOS, __FILE__, __LINE__
65
- def #{name}=(new_#{name})
66
- attributes[:#{name}] = [*new_#{name}]
67
- end
68
- EOS
69
- else
70
- if squash = options[:squash]
71
- class_eval <<-EOS, __FILE__, __LINE__
72
- def #{name}=(new_data)
73
- if new_data.is_a?(::Hash)
74
- if new_data.has_key?(:'#{squash}')
75
- attributes[:#{name}] = new_data[:'#{squash}']
76
- elsif new_data.has_key?("#{squash}")
77
- attributes[:#{name}] = new_data["#{squash}"]
78
- else
79
- attributes[:#{name}] = [ new_data ]
80
- end
81
- else
82
- attributes[:#{name}] = new_data
83
- end
84
- end
85
- EOS
24
+ def self.transforms
25
+ @transforms ||= {
26
+ :squash => Proc.new do |k, v, options|
27
+ squash = options[:squash]
28
+ if v.is_a?(::Hash)
29
+ if v.key?(squash.to_s.to_sym)
30
+ v[squash.to_s.to_sym]
31
+ elsif v.has_key?(squash.to_s)
32
+ v[squash.to_s]
86
33
  else
87
- class_eval <<-EOS, __FILE__, __LINE__
88
- def #{name}=(new_#{name})
89
- attributes[:#{name}] = new_#{name}
90
- end
91
- EOS
34
+ v
92
35
  end
36
+ else v
93
37
  end
94
- @attributes ||= []
95
- @attributes |= [name]
96
- for new_alias in [*options[:aliases]]
97
- aliases[new_alias] = name
98
- end
99
- end
38
+ end,
39
+ :none => lambda{|k, v, opts| v},
40
+ }
41
+ end
100
42
 
101
- def identity(name, options = {})
102
- @identity = name
103
- self.attribute(name, options)
104
- end
43
+ def self.default_parser
44
+ @default_parser ||= lambda{|v, opts| v}
45
+ end
105
46
 
106
- def ignore_attributes(*args)
107
- @ignored_attributes = args
108
- end
47
+ module ClassMethods
48
+ def _load(marshalled)
49
+ new(Marshal.load(marshalled))
50
+ end
109
51
 
110
- def ignored_attributes
111
- @ignored_attributes ||= []
112
- end
52
+ def aliases
53
+ @aliases ||= {}
54
+ end
113
55
 
56
+ def attributes
57
+ @attributes ||= []
114
58
  end
115
59
 
116
- module InstanceMethods
60
+ def attribute(name, options = {})
61
+ parser = Cistern::Attributes.parsers[options[:type]] ||
62
+ options[:parser] ||
63
+ Cistern::Attributes.default_parser
64
+ transform = Cistern::Attributes.transforms[options[:squash] ? :squash : :none] ||
65
+ Cistern::Attributes.default_transform
117
66
 
118
- def _dump(level)
119
- Marshal.dump(attributes)
67
+ self.send(:define_method, name) do
68
+ attributes[name.to_s.to_sym]
120
69
  end
121
70
 
122
- def attributes
123
- @attributes ||= {}
71
+ self.send(:define_method, "#{name}=") do |value|
72
+ transformed = transform.call(name, value, options)
73
+ attributes[name.to_s.to_sym]= parser.call(transformed, options)
124
74
  end
125
75
 
126
- def dup
127
- copy = super
128
- copy.dup_attributes!
129
- copy
130
- end
76
+ @attributes ||= []
77
+ @attributes |= [name]
131
78
 
132
- def identity
133
- send(self.class.instance_variable_get('@identity'))
79
+ for new_alias in [*options[:aliases]]
80
+ aliases[new_alias] = name
134
81
  end
82
+ end
135
83
 
136
- def identity=(new_identity)
137
- send("#{self.class.instance_variable_get('@identity')}=", new_identity)
138
- end
84
+ def identity(name, options = {})
85
+ @identity = name
86
+ self.attribute(name, options)
87
+ end
139
88
 
140
- def merge_attributes(new_attributes = {})
141
- for key, value in new_attributes
142
- unless self.class.ignored_attributes.include?(key)
143
- if aliased_key = self.class.aliases[key]
144
- send("#{aliased_key}=", value)
145
- elsif self.respond_to?("#{key}=",true)
146
- send("#{key}=", value)
147
- else
148
- attributes[key] = value
149
- end
150
- end
151
- end
152
- self
153
- end
89
+ def ignore_attributes(*args)
90
+ @ignored_attributes = args
91
+ end
154
92
 
155
- def new_record?
156
- !identity
157
- end
93
+ def ignored_attributes
94
+ @ignored_attributes ||= []
95
+ end
96
+ end
158
97
 
159
- # check that the attributes specified in args exist and is not nil
160
- def requires(*args)
161
- missing = missing_attributes(args)
162
- if missing.length == 1
163
- raise(ArgumentError, "#{missing.first} is required for this operation")
164
- elsif missing.any?
165
- raise(ArgumentError, "#{missing[0...-1].join(", ")} and #{missing[-1]} are required for this operation")
166
- end
167
- end
98
+ module InstanceMethods
99
+ def _dump(level)
100
+ Marshal.dump(attributes)
101
+ end
168
102
 
169
- def requires_one(*args)
170
- missing = missing_attributes(args)
171
- if missing.length == args.length
172
- raise(ArgumentError, "#{missing[0...-1].join(", ")} or #{missing[-1]} are required for this operation")
173
- end
174
- end
103
+ def attributes
104
+ @attributes ||= {}
105
+ end
175
106
 
176
- protected
107
+ def attributes=(attributes)
108
+ @attributes = attributes
109
+ end
110
+
111
+ def dup
112
+ copy = super
113
+ copy.attributes= copy.attributes.dup
114
+ copy
115
+ end
177
116
 
178
- def missing_attributes(args)
179
- missing = []
180
- for arg in [:connection] | args
181
- unless send("#{arg}") || attributes.has_key?(arg)
182
- missing << arg
117
+ def identity
118
+ send(self.class.instance_variable_get('@identity'))
119
+ end
120
+
121
+ def identity=(new_identity)
122
+ send("#{self.class.instance_variable_get('@identity')}=", new_identity)
123
+ end
124
+
125
+ def merge_attributes(new_attributes = {})
126
+ for key, value in new_attributes
127
+ unless self.class.ignored_attributes.include?(key)
128
+ if aliased_key = self.class.aliases[key]
129
+ send("#{aliased_key}=", value)
130
+ elsif self.respond_to?("#{key}=", true)
131
+ send("#{key}=", value)
132
+ else
133
+ attributes[key] = value
183
134
  end
184
135
  end
185
- missing
186
136
  end
137
+ self
138
+ end
187
139
 
188
- def dup_attributes!
189
- @attributes = @attributes.dup
140
+ def new_record?
141
+ !identity
142
+ end
143
+
144
+ # check that the attributes specified in args exist and is not nil
145
+ def requires(*args)
146
+ missing = missing_attributes(args)
147
+ if missing.length == 1
148
+ raise(ArgumentError, "#{missing.first} is required for this operation")
149
+ elsif missing.any?
150
+ raise(ArgumentError, "#{missing[0...-1].join(", ")} and #{missing[-1]} are required for this operation")
151
+ end
152
+ end
153
+
154
+ def requires_one(*args)
155
+ missing = missing_attributes(args)
156
+ if missing.length == args.length
157
+ raise(ArgumentError, "#{missing[0...-1].join(", ")} or #{missing[-1]} are required for this operation")
190
158
  end
159
+ end
191
160
 
192
- private
161
+ protected
193
162
 
194
- def remap_attributes(attributes, mapping)
195
- for key, value in mapping
196
- if attributes.key?(key)
197
- attributes[value] = attributes.delete(key)
198
- end
163
+ def missing_attributes(args)
164
+ missing = []
165
+ for arg in [:connection] | args
166
+ unless send("#{arg}") || attributes.has_key?(arg)
167
+ missing << arg
199
168
  end
200
169
  end
170
+ missing
201
171
  end
202
172
  end
203
173
  end
@@ -2,29 +2,23 @@ class Cistern::Collection < Array
2
2
  extend Cistern::Attributes::ClassMethods
3
3
  include Cistern::Attributes::InstanceMethods
4
4
 
5
- Array.public_instance_methods(false).each do |method|
6
- unless [:reject, :select, :slice].include?(method.to_sym)
7
- class_eval <<-EOS, __FILE__, __LINE__
8
- def #{method}(*args)
9
- unless @loaded
10
- lazy_load
11
- end
12
- super
13
- end
14
- EOS
5
+ %w[reject select slice].each do |method|
6
+ define_method(method) do |*args, &block|
7
+ unless @loaded
8
+ lazy_load
9
+ end
10
+ data = super(*args, &block)
11
+ self.clone.clear.concat(data)
15
12
  end
16
13
  end
17
14
 
18
- %w[reject select slice].each do |method|
19
- class_eval <<-EOS, __FILE__, __LINE__
20
- def #{method}(*args)
21
- unless @loaded
22
- lazy_load
23
- end
24
- data = super
25
- self.clone.clear.concat(data)
15
+ %w[first last].each do |method|
16
+ define_method(method) do
17
+ unless @loaded
18
+ lazy_load
26
19
  end
27
- EOS
20
+ super()
21
+ end
28
22
  end
29
23
 
30
24
  def self.model(new_model=nil)
@@ -80,40 +74,12 @@ class Cistern::Collection < Array
80
74
  self
81
75
  end
82
76
 
83
- def inspect
84
- Thread.current[:formatador] ||= Formatador.new
85
- data = "#{Thread.current[:formatador].indentation}<#{self.class.name}\n"
86
- Thread.current[:formatador].indent do
87
- unless self.class.attributes.empty?
88
- data << "#{Thread.current[:formatador].indentation}"
89
- data << self.class.attributes.map {|attribute| "#{attribute}=#{send(attribute).inspect}"}.join(",\n#{Thread.current[:formatador].indentation}")
90
- data << "\n"
91
- end
92
- data << "#{Thread.current[:formatador].indentation}["
93
- unless self.empty?
94
- data << "\n"
95
- Thread.current[:formatador].indent do
96
- data << self.map {|member| member.inspect}.join(",\n")
97
- data << "\n"
98
- end
99
- data << Thread.current[:formatador].indentation
100
- end
101
- data << "]\n"
102
- end
103
- data << "#{Thread.current[:formatador].indentation}>"
104
- data
105
- end
106
-
107
77
  def reload
108
78
  clear
109
79
  lazy_load
110
80
  self
111
81
  end
112
82
 
113
- def table(attributes = nil)
114
- Formatador.display_table(self.map {|instance| instance.attributes}, attributes)
115
- end
116
-
117
83
  private
118
84
 
119
85
  def lazy_load
@@ -0,0 +1,5 @@
1
+ module Cistern::Formatter
2
+ autoload :AwesomePrint, 'cistern/formatters/awesome_print'
3
+ autoload :Default, 'cistern/formatters/default'
4
+ autoload :Formatador, 'cistern/formatters/formatador'
5
+ end
@@ -0,0 +1,31 @@
1
+ require 'awesome_print'
2
+
3
+ module Cistern::Formatter::AwesomePrint
4
+ def self.call(model)
5
+ model.ai
6
+ end
7
+ end
8
+
9
+ module AwesomePrint::Cistern
10
+ def self.included(base)
11
+ base.send :alias_method, :cast_without_cistern, :cast
12
+ base.send :alias_method, :cast, :cast_with_cistern
13
+ end
14
+
15
+ def cast_with_cistern(object, type)
16
+ cast = cast_without_cistern(object, type)
17
+ if object.is_a?(Cistern::Model)
18
+ cast = :cistern_model
19
+ end
20
+ cast
21
+ end
22
+
23
+ # Format Cistern::Model
24
+ #------------------------------------------------------------------------------
25
+ def awesome_cistern_model(object)
26
+ data = object.attributes.keys.inject({}){|r,k| r.merge(k => object.send(k))}
27
+ "#{object} " << awesome_hash(data)
28
+ end
29
+ end
30
+
31
+ AwesomePrint::Formatter.send(:include, AwesomePrint::Cistern)
@@ -0,0 +1,5 @@
1
+ module Cistern::Formatter::Default
2
+ def self.call(obj)
3
+ "#<%s:0x%x attributes={%s}>" % [obj.class, obj.object_id.abs*2, obj.attributes.map{|k,v| "#{k}:#{v.inspect}"}.join(",")]
4
+ end
5
+ end
@@ -0,0 +1,44 @@
1
+ require 'formatador'
2
+
3
+ module Cistern::Formatter::Formatador
4
+ def self.call(model)
5
+ Thread.current[:formatador] ||= Formatador.new
6
+ data = "#{Thread.current[:formatador].indentation}<#{model.class.name}"
7
+ Thread.current[:formatador].indent do
8
+ unless model.class.attributes.empty?
9
+ data << "\n#{Thread.current[:formatador].indentation}"
10
+ data << model.class.attributes.map {|attribute| "#{attribute}=#{model.send(attribute).inspect}"}.join(",\n#{Thread.current[:formatador].indentation}")
11
+ end
12
+ end
13
+ data << "\n#{Thread.current[:formatador].indentation}>"
14
+ data
15
+ end
16
+
17
+ def inspect
18
+ Thread.current[:formatador] ||= Formatador.new
19
+ data = "#{Thread.current[:formatador].indentation}<#{self.class.name}\n"
20
+ Thread.current[:formatador].indent do
21
+ unless self.class.attributes.empty?
22
+ data << "#{Thread.current[:formatador].indentation}"
23
+ data << self.class.attributes.map {|attribute| "#{attribute}=#{send(attribute).inspect}"}.join(",\n#{Thread.current[:formatador].indentation}")
24
+ data << "\n"
25
+ end
26
+ data << "#{Thread.current[:formatador].indentation}["
27
+ unless self.empty?
28
+ data << "\n"
29
+ Thread.current[:formatador].indent do
30
+ data << self.map {|member| member.inspect}.join(",\n")
31
+ data << "\n"
32
+ end
33
+ data << Thread.current[:formatador].indentation
34
+ end
35
+ data << "]\n"
36
+ end
37
+ data << "#{Thread.current[:formatador].indentation}>"
38
+ data
39
+ end
40
+
41
+ def table(attributes = nil)
42
+ Formatador.display_table(self.map {|instance| instance.attributes}, attributes)
43
+ end
44
+ end
data/lib/cistern/model.rb CHANGED
@@ -4,23 +4,21 @@ class Cistern::Model
4
4
 
5
5
  attr_accessor :collection, :connection
6
6
 
7
- def initialize(attributes={})
8
- merge_attributes(attributes)
7
+ def self.formatter
8
+ @formatter ||= Cistern::Formatter::Default
9
+ end
10
+
11
+ def self.formatter=(formatter)
12
+ @formatter = formatter
9
13
  end
10
14
 
11
15
  def inspect
12
- Thread.current[:formatador] ||= Formatador.new
13
- data = "#{Thread.current[:formatador].indentation}<#{self.class.name}"
14
- Thread.current[:formatador].indent do
15
- unless self.class.attributes.empty?
16
- data << "\n#{Thread.current[:formatador].indentation}"
17
- data << self.class.attributes.map {|attribute| "#{attribute}=#{send(attribute).inspect}"}.join(",\n#{Thread.current[:formatador].indentation}")
18
- end
19
- end
20
- data << "\n#{Thread.current[:formatador].indentation}>"
21
- data
16
+ self.class.formatter.call(self)
22
17
  end
23
18
 
19
+ def initialize(attributes={})
20
+ merge_attributes(attributes)
21
+ end
24
22
 
25
23
  def save
26
24
  raise NotImplementedError
@@ -1,3 +1,3 @@
1
1
  module Cistern
2
- VERSION = "0.0.3"
2
+ VERSION = "0.1.2"
3
3
  end
data/lib/cistern.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  require 'cistern/version'
2
- require 'formatador'
2
+ require 'time'
3
3
 
4
4
  module Cistern
5
5
  Error = Class.new(StandardError)
@@ -12,6 +12,9 @@ module Cistern
12
12
  require 'cistern/model'
13
13
  require 'cistern/service'
14
14
 
15
+ autoload :Formatter, 'cistern/formatter'
16
+
17
+
15
18
  def self.timeout=(timeout)
16
19
  @timeout= timeout
17
20
  end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Cistern::Collection" do
4
+ class SampleCollectionModel < Cistern::Model
5
+ identity :id
6
+ attribute :name
7
+ end
8
+ class SampleCollection < Cistern::Collection
9
+ model SampleCollectionModel
10
+
11
+ def all
12
+ self.load([{id: 1}, {id: 3, name: "tom"}, {id: 2}])
13
+ end
14
+ end
15
+
16
+ it "should give first" do
17
+ SampleCollection.new.first.should == SampleCollectionModel.new(id: 1)
18
+ end
19
+
20
+ it "should give last" do
21
+ SampleCollection.new.last.should == SampleCollectionModel.new(id: 2)
22
+ end
23
+
24
+ it "should reject" do
25
+ SampleCollection.new.reject{|m| m.id == 2}.should == [SampleCollectionModel.new(id: 1), SampleCollectionModel.new(id: 3)]
26
+ end
27
+
28
+ it "should select" do
29
+ SampleCollection.new.select{|m| m.id == 2}.should == [SampleCollectionModel.new(id: 2)]
30
+ end
31
+
32
+ it "should slice" do
33
+ SampleCollection.new.slice(0,2).should == [SampleCollectionModel.new(id: 1), SampleCollectionModel.new(id: 3, name: "tom")]
34
+ end
35
+ end
@@ -0,0 +1,108 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Cistern::Model" do
4
+
5
+ it "should duplicate a model" do
6
+ class DupSpec < Cistern::Model
7
+ identity :id
8
+ attribute :name
9
+ attribute :properties
10
+ end
11
+
12
+ model = DupSpec.new(id: 1, name: "string", properties: {value: "something", else: "what"})
13
+ duplicate = model.dup
14
+
15
+ duplicate.should == model
16
+ duplicate.should_not eql model
17
+
18
+ model.name= "anotherstring"
19
+ duplicate.name.should == "string"
20
+ end
21
+
22
+ context "attribute parsing" do
23
+ class TypeSpec < Cistern::Model
24
+ identity :id
25
+ attribute :name, type: :string
26
+ attribute :created_at, type: :time
27
+ attribute :flag, type: :boolean
28
+ attribute :list, type: :array
29
+ attribute :number, type: :integer
30
+ attribute :floater, type: :float
31
+ attribute :butternut, type: :integer, aliases: "squash", squash: "id"
32
+ attribute :custom, parser: lambda{|v, opts| "X!#{v}"}
33
+ end
34
+
35
+ it "should parse string" do
36
+ TypeSpec.new(name: 1).name.should == "1"
37
+ end
38
+
39
+ it "should parse time" do
40
+ time = Time.now
41
+ created_at = TypeSpec.new(created_at: time.to_s).created_at
42
+ created_at.should be_a(Time)
43
+ created_at.to_i.should == time.to_i
44
+ end
45
+
46
+ it "should parse boolean" do
47
+ TypeSpec.new(flag: "false").flag.should be_false
48
+ TypeSpec.new(flag: "true").flag.should be_true
49
+ TypeSpec.new(flag: false).flag.should be_false
50
+ TypeSpec.new(flag: true).flag.should be_true
51
+ TypeSpec.new(flag: "0").flag.should be_false
52
+ TypeSpec.new(flag: "1").flag.should be_true
53
+ TypeSpec.new(flag: 0).flag.should be_false
54
+ TypeSpec.new(flag: 1).flag.should be_true
55
+ end
56
+
57
+ it "should parse an array" do
58
+ TypeSpec.new(list: []).list.should == []
59
+ TypeSpec.new(list: "item").list.should == ["item"]
60
+ end
61
+
62
+ it "should parse a float" do
63
+ TypeSpec.new(floater: "0.01").floater.should == 0.01
64
+ TypeSpec.new(floater: 0.01).floater.should == 0.01
65
+ end
66
+
67
+ it "should use custom parser" do
68
+ TypeSpec.new(custom: "15").custom.should == "X!15"
69
+ end
70
+
71
+ it "should squash and cast" do
72
+ TypeSpec.new({"squash" => {"id" => "12"}}).butternut.should == 12
73
+ end
74
+ end
75
+
76
+ context "inspection engine" do
77
+ class InspectorSpec < Cistern::Model
78
+ identity :id
79
+ attribute :name
80
+ end
81
+
82
+ after(:all) do
83
+ InspectorSpec.formatter= Cistern::Formatter::Default
84
+ end
85
+
86
+ it "should default to default formatter" do
87
+ InspectorSpec.formatter.should == Cistern::Formatter::Default
88
+ end
89
+
90
+ it "should use default" do
91
+ InspectorSpec.new(id: 1, name: "name").inspect.should match /#<InspectorSpec:0x[0-9a-f]+ attributes={id:1,name:\"name\"}/
92
+ end
93
+
94
+ it "should use awesome_print" do
95
+ defined?(AwesomePrint).should be_false # don't require if not used
96
+ InspectorSpec.formatter= Cistern::Formatter::AwesomePrint
97
+
98
+ InspectorSpec.new(id: 1, name: "name").inspect.match /(?x-mi:\#<InspectorSpec:0x[0-9a-f]+>\ {\n\ \ \ \ \ \ :id\x1B\[0;37m\ =>\ \x1B\[0m\x1B\[1;34m1\x1B\[0m,\n\ \ \ \ :name\x1B\[0;37m\ =>\ \x1B\[0m\x1B\[0;33m"name"\x1B\[0m\n})/
99
+ end
100
+
101
+ it "should use formatador" do
102
+ defined?(Formatador).should be_false # don't require if not used
103
+ InspectorSpec.formatter= Cistern::Formatter::Formatador
104
+
105
+ InspectorSpec.new(id: 1, name: "name").inspect.should == " <InspectorSpec\n id=1,\n name=\"name\"\n >"
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,6 @@
1
+ require File.expand_path('../../lib/cistern', __FILE__)
2
+
3
+ Bundler.require(:test)
4
+
5
+ RSpec.configure do
6
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cistern
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.1.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,24 +9,8 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-07-21 00:00:00.000000000 Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
15
- name: formatador
16
- requirement: !ruby/object:Gem::Requirement
17
- none: false
18
- requirements:
19
- - - ! '>='
20
- - !ruby/object:Gem::Version
21
- version: '0'
22
- type: :runtime
23
- prerelease: false
24
- version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
- requirements:
27
- - - ! '>='
28
- - !ruby/object:Gem::Version
29
- version: '0'
12
+ date: 2012-11-30 00:00:00.000000000 Z
13
+ dependencies: []
30
14
  description: API client framework extracted from Fog
31
15
  email:
32
16
  - me@joshualane.com
@@ -36,6 +20,7 @@ extra_rdoc_files: []
36
20
  files:
37
21
  - .gitignore
38
22
  - Gemfile
23
+ - Guardfile
39
24
  - LICENSE
40
25
  - README.md
41
26
  - Rakefile
@@ -43,13 +28,20 @@ files:
43
28
  - lib/cistern.rb
44
29
  - lib/cistern/attributes.rb
45
30
  - lib/cistern/collection.rb
31
+ - lib/cistern/formatter.rb
32
+ - lib/cistern/formatters/awesome_print.rb
33
+ - lib/cistern/formatters/default.rb
34
+ - lib/cistern/formatters/formatador.rb
46
35
  - lib/cistern/hash.rb
47
36
  - lib/cistern/mock.rb
48
37
  - lib/cistern/model.rb
49
38
  - lib/cistern/service.rb
50
39
  - lib/cistern/version.rb
51
40
  - lib/cistern/wait_for.rb
52
- homepage: ''
41
+ - spec/collection_spec.rb
42
+ - spec/model_spec.rb
43
+ - spec/spec_helper.rb
44
+ homepage: http://joshualane.com/cistern
53
45
  licenses: []
54
46
  post_install_message:
55
47
  rdoc_options: []
@@ -73,4 +65,7 @@ rubygems_version: 1.8.24
73
65
  signing_key:
74
66
  specification_version: 3
75
67
  summary: API client framework
76
- test_files: []
68
+ test_files:
69
+ - spec/collection_spec.rb
70
+ - spec/model_spec.rb
71
+ - spec/spec_helper.rb