metahash-rb 1.0.4 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 798330d85a54d6b19e38d12e21bc34c61584ef3d
4
- data.tar.gz: fd78187595fcbd822ff50808d0b7fd1b60c76ba3
3
+ metadata.gz: c50e809216c3a73ef2046daea65464fa70523202
4
+ data.tar.gz: 24b5731caac076b56137652e1aef1811eb7af6e3
5
5
  SHA512:
6
- metadata.gz: 0054823568ecbd5370c4cbeae8defb83ce057b8ae6cf52aa158c8454076cce61f0ef176c36063644d12f5192f09126f0ec0d2fb8c59139d2ce0ca93b2d4b263d
7
- data.tar.gz: e3254e4a03ecb41c76d84e028b288855375f276e9fb9ea58c2e39f970dc63327934364c9ce540f45d20c6b35f36898fa14a5dbb2d0c2c21d15531dfc2c66337a
6
+ metadata.gz: 229d38b0eb040f5bc90e6eed6f2e173411647b1195d5544c0aeb1f3dc632f0f81dfb7d7a637b5b879f2de74c7d8dece3f71bf1e53e981df03799a962b024397d
7
+ data.tar.gz: d4c9b695e64e7ebb188997f1b0491e5e27268a838c9e1f7b902c8837f6801faa31c14cfed2727a4bb068209ffa3fda762996b33df5caed284bb328236144046a
data/.travis.yml ADDED
@@ -0,0 +1,15 @@
1
+ language: ruby
2
+ bundler_args: --without guard
3
+ rvm:
4
+ - "2.0"
5
+ - "2.1"
6
+ - "2.1.1"
7
+ - ruby-head
8
+ script: "bundle exec rspec"
9
+ addons:
10
+ code_climate:
11
+ repo_token: 1d1b1a31bb3137d986297ad8a1ad5a3a1adbd70f0e8583d7eaf1dd4c0ab0bbe1
12
+ branches:
13
+ only: master
14
+ notifications:
15
+ email: false
data/README.md CHANGED
@@ -2,7 +2,7 @@ MetaHash
2
2
  ========
3
3
 
4
4
  [![Gem Version](https://badge.fury.io/rb/metahash-rb.svg)](http://badge.fury.io/rb/metahash-rb)
5
- [![](https://ci.solanolabs.com:443/TinderBox/MetaHash/badges/110842.png?badge_token=a5097ea0ff487d291e94285ed9e4c8fabeca5fd1)](https://ci.solanolabs.com:443/TinderBox/MetaHash/suites/110842)
5
+ [![Build Status](https://travis-ci.org/NullVoxPopuli/MetaHash.svg)](https://travis-ci.org/NullVoxPopuli/MetaHash)
6
6
  [![Code Climate](https://codeclimate.com/github/NullVoxPopuli/MetaHash/badges/gpa.svg)](https://codeclimate.com/github/NullVoxPopuli/MetaHash)
7
7
  [![Dependency Status](https://gemnasium.com/NullVoxPopuli/MetaHash.svg)](https://gemnasium.com/NullVoxPopuli/MetaHash)
8
8
  [![Test Coverage](https://codeclimate.com/github/NullVoxPopuli/MetaHash/badges/coverage.svg)](https://codeclimate.com/github/NullVoxPopuli/MetaHash)
@@ -14,18 +14,45 @@ Provides a subclass of Hash and a wrapper around Rails' serialize attribute for
14
14
  ## Examples
15
15
  #### Access nested hashes using method / object syntax
16
16
 
17
+ Arand new Metadata objects act just like hashes:
18
+
17
19
  h = Metadata.new
18
- h # => {}
19
- h.outer.inner # => {}
20
+ h
21
+ => {}
22
+
23
+ Accessing nested data requires no wrapping conditions checking for existence of the rquested data:
24
+
25
+ h.outer.inner
26
+ => {}
27
+
28
+ Possible real-word example:
29
+
30
+ if (min_numbers = h.password_rules.formats.numbers.minimum).present?
31
+ # some code using min_numbers
32
+ else
33
+ # data doesn't exist in h
34
+
35
+ h.password_rules.formats.numbers.minimum = 1
36
+ # h
37
+ # => { password_rules: { formats: { numbers: { minimum: 1 } } } }
38
+ end
20
39
 
21
40
  #### Access to values stored in nested hashes via method call syntax
22
41
 
23
42
  h = Metadata.new( { outer: { inner: { hash_key: "value" } } } )
24
- h.outer.inner.hash_key # => "value"
43
+
44
+ h.outer.inner.hash_key
45
+ => "value"
25
46
 
26
47
  #### Set values for nested hash structures without the nested hashes having to be initially defined
27
48
 
28
- h = Metadata.new( {} )
49
+ h = Metadata.new
50
+ h
51
+ => {}
52
+
53
+ h.outer.inner = 2
54
+ h
55
+ => { outer: { inner: 2 } }
29
56
 
30
57
  ## Using with ActiveRecord
31
58
 
@@ -54,3 +81,5 @@ This gem has been tested with Ruby 2.0, and rails 3.2, 4.1
54
81
  3. Add Test(s)!
55
82
  4. Commit your proposed changes
56
83
  5. Submit a pull request
84
+
85
+ [![Analytics](https://ga-beacon.appspot.com/UA-54618821-1/your-repo/page-name)](https://github.com/igrigorik/ga-beacon)
data/lib/metahash.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require "metahash/metaclass"
2
2
  require "metahash/metadata"
3
+ require "metahash/extensions/hash/to_metadata"
3
4
  require "metahash/version"
4
5
  require 'active_record'
5
6
 
@@ -10,7 +11,7 @@ module MetaHash
10
11
  # the hash by creating class Metadata < Hash; end
11
12
  #
12
13
  # @param [Symbol] serialized_field name of the field to convert to Metadata
13
- def has_metadata(serialized_field = "metadata", serializer: JSON)
14
+ def has_metadata( serialized_field = "metadata", serializer: JSON )
14
15
  # tell Active Record that the field is going to be JSON
15
16
  # serialized, because JSON > YAML
16
17
  serialize serialized_field, serializer
@@ -19,33 +20,39 @@ module MetaHash
19
20
  # first check the type of the field
20
21
  # proceed if hash, abort if Metadata
21
22
  if record.has_attribute?(serialized_field)
22
- if [Hash, NilClass].include?(record.send(serialized_field).class)
23
+ if [ Hash, NilClass ].include?( record.send( serialized_field ).class )
23
24
  # alias the old method / field
24
25
  backup_name = "#{serialized_field}_original".to_sym
26
+
25
27
  # alias_method backup_name, serialized_field
26
- record.define_singleton_method backup_name, record.method(serialized_field)
28
+ record.define_singleton_method( backup_name, record.method( serialized_field ) )
29
+
27
30
  # name the metadata accessor the same as the original field
28
31
  # rails should automatically serialize this on save
29
- initial_value = record.send(backup_name) || {}
30
- record.send("#{serialized_field}=", Metadata.new(initial_value))
32
+ initial_value = record.send( backup_name) || {}
33
+ record.send( "#{serialized_field}=", Metadata.new( initial_value ) )
31
34
  end
32
35
  end
33
36
  end
34
37
 
38
+ build_save_hooks( serialized_field )
39
+ end
35
40
 
41
+ private
42
+
43
+ def build_save_hooks( serialized_field )
36
44
  # create a before_save hook to store a pure Hash in the DB
37
45
  before_save do |record|
38
- @temp_metadata = record.send(serialized_field)
39
- record.send("#{serialized_field}=", @temp_metadata.to_hash) if @temp_metadata
46
+ @temp_metadata = record.send( serialized_field )
47
+ record.send( "#{serialized_field}=", @temp_metadata.to_hash ) if @temp_metadata
40
48
  end
41
49
 
42
50
  # restore the metadata to the field
43
51
  after_save do |record|
44
- record.send("#{serialized_field}=", @temp_metadata) if @temp_metadata
52
+ record.send( "#{serialized_field}=", @temp_metadata ) if @temp_metadata
45
53
  end
46
-
47
54
  end
48
55
 
49
56
  end
50
57
 
51
- ActiveRecord::Base.send :extend, MetaHash
58
+ ActiveRecord::Base.send( :extend, MetaHash )
@@ -0,0 +1,9 @@
1
+ class Hash
2
+ # Returns a copy of self represented as a Metahash
3
+ #
4
+ # m = { a: 1 }.to_metadata
5
+ # m.a # => 1
6
+ def to_metadata
7
+ Metadata.new(self)
8
+ end
9
+ end
@@ -4,16 +4,28 @@
4
4
  # particular class
5
5
  module Metaclass
6
6
  # The hidden singleton lurks behind everyone
7
- def metaclass; class << self; self; end; end
8
- def meta_eval &blk; metaclass.instance_eval &blk; end
7
+ def metaclass
8
+ class << self
9
+ self
10
+ end
11
+ end
12
+
13
+ def meta_eval(&block)
14
+ metaclass.instance_eval(&block)
15
+ end
9
16
 
10
17
  # Adds methods to a metaclass
11
- def meta_def( name, &blk )
12
- meta_eval { define_method name, &blk }
18
+ def meta_def(name, &block)
19
+ meta_eval {
20
+ define_method(name, &block)
21
+ }
13
22
  end
14
23
 
24
+ # unused
15
25
  # Defines an instance method within a class
16
- def class_def( name, &blk )
17
- class_eval { define_method name, &blk }
18
- end
26
+ # def class_def(name, &block)
27
+ # class_eval {
28
+ # define_method(name, &block)
29
+ # }
30
+ # end
19
31
  end
@@ -44,7 +44,7 @@ class Metadata < Hash
44
44
  # recursively create nested metadata objects
45
45
  hash.each do |key, value|
46
46
 
47
- self[key] = (
47
+ self[ key ] = (
48
48
  if value.is_a?(Hash)
49
49
  Metadata.new(value)
50
50
  elsif value.is_a?(Array)
@@ -70,20 +70,7 @@ class Metadata < Hash
70
70
  if (key = method_name.to_s).include?("=")
71
71
  key = key.chop.to_sym
72
72
 
73
- deepest_metadata = self
74
- if not @empty_nested_hashes.empty?
75
- @empty_nested_hashes.each do |key|
76
- deepest_metadata = deepest_metadata[key] = Metadata.new
77
- end
78
- @empty_nested_hashes = []
79
- deepest_metadata[key] = args[0]
80
- # override any existing method with the key
81
- deepest_metadata.meta_def(key){ self[key]}
82
- else
83
- self[key] = args[0]
84
- # override any existing method with the key
85
- self.meta_def(key){ args[0] }
86
- end
73
+ assign_value(key, args[0])
87
74
  else
88
75
  value = self[method_name]
89
76
  if not value
@@ -134,4 +121,27 @@ class Metadata < Hash
134
121
  def to_ary
135
122
  self.to_hash.to_a
136
123
  end
124
+
125
+ alias_method :to_a, :to_ary
126
+
127
+ private
128
+
129
+ def assign_value(key, value)
130
+ deepest_metadata = self
131
+
132
+ if not @empty_nested_hashes.empty?
133
+ @empty_nested_hashes.each do |key|
134
+ deepest_metadata = deepest_metadata[key] = Metadata.new
135
+ end
136
+
137
+ @empty_nested_hashes = []
138
+ deepest_metadata[key] = value
139
+ # override any existing method with the key
140
+ deepest_metadata.meta_def(key){ self[key] }
141
+ else
142
+ self[key] = value
143
+ # override any existing method with the key
144
+ self.meta_def(key){ value }
145
+ end
146
+ end
137
147
  end
@@ -1,3 +1,3 @@
1
1
  module MetaHash
2
- VERSION = "1.0.4"
2
+ VERSION = "1.1.0"
3
3
  end
data/spec/hash_spec.rb ADDED
@@ -0,0 +1,9 @@
1
+ require "spec_helper"
2
+
3
+ describe Hash do
4
+ context "to_metadata" do
5
+ subject(:h){ { a: 1 }.to_metadata }
6
+
7
+ it { is_expected.to be_a Metadata }
8
+ end
9
+ end
@@ -6,6 +6,95 @@ describe Metadata do
6
6
  expect(Metadata.new).to be_kind_of(Hash)
7
7
  end
8
8
 
9
+ context 'instance methods' do
10
+ let(:m){ Metadata.new(h) }
11
+
12
+ describe "[]" do
13
+ let(:key){h.keys.first}
14
+
15
+ it "retrieves with a string key" do
16
+ expect(m[key.to_s]).to eq h[key]
17
+ end
18
+
19
+ it "retrieves with a symbol key" do
20
+ expect(m[key.to_sym]).to eq h[key]
21
+ end
22
+ end
23
+
24
+ describe "[]=" do
25
+
26
+ it 'sets with a string key' do
27
+ m["a"] = 2
28
+ expect(m[:a]).to eq 2
29
+ end
30
+
31
+ it 'sets with a symbol key' do
32
+ m[:b] = 2
33
+ expect(m["b"]).to eq 2
34
+ end
35
+
36
+ end
37
+
38
+ describe "valid_key?" do
39
+
40
+ it "is true for keys that aren't methods" do
41
+ expect(m.valid_key?(:b)).to eq true
42
+ end
43
+
44
+ it "is false for existing methods" do
45
+ expect(m.valid_key?(:to_hash)).to eq false
46
+ end
47
+ end
48
+
49
+ describe "to_hash" do
50
+
51
+ it "converts to a hash" do
52
+ expect(m.to_hash).to_not be_kind_of Metadata
53
+ end
54
+
55
+ it "converts arrays" do
56
+ h = hash_with_array
57
+ m = Metadata.new(h)
58
+ expect(m.to_hash).to_not respond_to :array
59
+ expect(m.to_hash[:array]).to be_a Array
60
+ end
61
+
62
+ end
63
+
64
+ describe "to_ary or to_a" do
65
+
66
+ it "converts the hash to an array" do
67
+ expect(m.to_a).to eq m.to_hash.to_a
68
+ end
69
+
70
+ end
71
+
72
+ describe "initialize" do
73
+
74
+ it "copies hash contents" do
75
+ expect(Metadata.new(h)).to eq h
76
+ end
77
+
78
+ it "returns the argument" do
79
+ m = Metadata.new
80
+ expect(Metadata.new(m)).to eq m
81
+ end
82
+
83
+ it "creates metadata objects in an array" do
84
+ h = hash_with_array
85
+ m = Metadata.new(h)
86
+
87
+ expect(m.array.first.a).to eq 2
88
+ expect(m.array.last.b).to eq 3
89
+ end
90
+
91
+ it "raises an error with invalid input" do
92
+ expect{Metadata.new(2)}.to raise_error
93
+ end
94
+ end
95
+
96
+ end
97
+
9
98
  describe "pruning empty hashes" do
10
99
  let(:m){Metadata.new}
11
100
 
@@ -56,6 +145,13 @@ describe Metadata do
56
145
  expect(m.a.keys).to eq 3
57
146
  end
58
147
 
148
+ it "can overrid min and max of deeply nested hashes" do
149
+ m.password_rules.formats.digits.max = 3
150
+ m.password_rules.formats.digits.min = 2
151
+
152
+ expect(m.password_rules.formats.digits.min).to eq 2
153
+ expect(m.password_rules.formats.digits.max).to eq 3
154
+ end
59
155
  end
60
156
 
61
157
 
data/spec/spec_helper.rb CHANGED
@@ -1,11 +1,18 @@
1
1
 
2
2
  require "rubygems"
3
3
  require "bundler/setup"
4
- require "metahash"
4
+
5
5
  require "pry-byebug" # binding.pry to debug!
6
+
7
+ # Coverage
6
8
  require "codeclimate-test-reporter"
9
+ ENV['CODECLIMATE_REPO_TOKEN'] = "1d1b1a31bb3137d986297ad8a1ad5a3a1adbd70f0e8583d7eaf1dd4c0ab0bbe1"
7
10
  CodeClimate::TestReporter.start
8
11
 
12
+ # This Gem
13
+ require "metahash"
14
+
15
+
9
16
  ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:"
10
17
  load File.dirname(__FILE__) + '/support/schema.rb'
11
18
  Dir[File.dirname(__FILE__) + '/support/**/*.rb'].each {|file| require file }
@@ -7,3 +7,12 @@ def h
7
7
  }
8
8
  }
9
9
  end
10
+
11
+ def hash_with_array
12
+ {
13
+ array: [
14
+ { a: 2 },
15
+ { b: 3 }
16
+ ]
17
+ }
18
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: metahash-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - L. Preston Sego III
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-09 00:00:00.000000000 Z
11
+ date: 2014-09-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -103,22 +103,24 @@ extra_rdoc_files: []
103
103
  files:
104
104
  - ".gitignore"
105
105
  - ".rspec"
106
+ - ".travis.yml"
106
107
  - Gemfile
107
108
  - LICENSE
108
109
  - README.md
109
110
  - Rakefile
110
111
  - lib/metahash.rb
112
+ - lib/metahash/extensions/hash/to_metadata.rb
111
113
  - lib/metahash/metaclass.rb
112
114
  - lib/metahash/metadata.rb
113
115
  - lib/metahash/version.rb
114
116
  - metahash.gemspec
117
+ - spec/hash_spec.rb
115
118
  - spec/metadata_spec.rb
116
119
  - spec/metahash_spec.rb
117
120
  - spec/spec_helper.rb
118
121
  - spec/support/models/test_object.rb
119
122
  - spec/support/sample_hashes.rb
120
123
  - spec/support/schema.rb
121
- - tddium.yml
122
124
  homepage: https://github.com/NullVoxPopuli/MetaHash
123
125
  licenses:
124
126
  - MIT
@@ -142,8 +144,9 @@ rubyforge_project:
142
144
  rubygems_version: 2.4.1
143
145
  signing_key:
144
146
  specification_version: 4
145
- summary: MetaHash-1.0.4
147
+ summary: MetaHash-1.1.0
146
148
  test_files:
149
+ - spec/hash_spec.rb
147
150
  - spec/metadata_spec.rb
148
151
  - spec/metahash_spec.rb
149
152
  - spec/spec_helper.rb
data/tddium.yml DELETED
@@ -1,3 +0,0 @@
1
- :tddium:
2
- :ruby_version: ruby-2.1.2
3
- :coverage: true