simple-immutable 1.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,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ee7113a903d3124b8d4c64499cc3dcd3ae296d6d4b45c6178b5205c3baae8675
4
+ data.tar.gz: 722814d2e633c8a7ea57c71b5add682ee62f46bffc113ad2047bc1b281dc9516
5
+ SHA512:
6
+ metadata.gz: a6328926689c3ded5d5e6a3ae4f24b0fcc73663ef0d2aec26019c0ec6fc705c8f7da903fcb9aba8a917c75884b3299f603d3f521af95bf5cd4b7d7dd6f8c2c0c
7
+ data.tar.gz: adae1e19d19f7ce6a4c152b6137d27689c679d11ca91150bf04fd49115f8ba67ec080f1f2ba965e2e8111a08ce6ef3b58b4ef7bdefbb9730adadd63a6ff434b2
@@ -0,0 +1,10 @@
1
+ coverage
2
+ rdoc
3
+ pkg
4
+ log/test.log
5
+ .rspec.data
6
+ Gemfile.lock
7
+ .rake_t_cache
8
+ .rspec.status
9
+ .DS_Store
10
+ tmp
@@ -0,0 +1,9 @@
1
+ # Settings
2
+ fontName = "Menlo"
3
+ fontSize = 13
4
+ fileBrowserGlob = "{*,.tm_properties,.htaccess,}"
5
+ excludeDirectories = "{node_modules,coverage,log,}"
6
+
7
+ # Variables
8
+ PATH = "$PATH:$HOME/bin"
9
+ TM_GIT = "/opt/local/bin/git"
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in {gemname}.gemspec
4
+ gemspec
@@ -0,0 +1,7 @@
1
+ default: test
2
+
3
+ test:
4
+ ruby lib/simple/immutable.rb
5
+
6
+ release:
7
+ scripts/release.rb
@@ -0,0 +1,38 @@
1
+ # simple-immutable
2
+
3
+ Turns a nested data structure into a immutable ruby object implementing dot and [] accessors.
4
+
5
+ ## Usage
6
+
7
+
8
+ Immutable = ::Simple::Immutable
9
+
10
+ data =
11
+ {
12
+ a: "a-value",
13
+ "b": "b-value",
14
+ "child": {
15
+ name: "childname",
16
+ grandchild: {
17
+ name: "grandchildname"
18
+ }
19
+ },
20
+ "children": [
21
+ "anna",
22
+ "arthur",
23
+ {
24
+ action: {
25
+ keep_your_mouth_shut: true
26
+ }
27
+ }
28
+ ]
29
+ }
30
+
31
+ imm = Immutable.create(data)
32
+
33
+ imm.a # -> 'a-value'
34
+ imm.children.class # -> Array
35
+ imm.children[2].action.keep_your_mouth_shut # -> true
36
+ imm.children.foo # NoMethodError (undefined method `foo' for #<Array:0x00007fb90f1be390>)
37
+ imm.children.first.foo # NoMethodError (undefined method `foo' for "anna":String)
38
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.1
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'bundle' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "rubygems"
12
+
13
+ m = Module.new do
14
+ module_function
15
+
16
+ def invoked_as_script?
17
+ File.expand_path($0) == File.expand_path(__FILE__)
18
+ end
19
+
20
+ def env_var_version
21
+ ENV["BUNDLER_VERSION"]
22
+ end
23
+
24
+ def cli_arg_version
25
+ return unless invoked_as_script? # don't want to hijack other binstubs
26
+ return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
27
+ bundler_version = nil
28
+ update_index = nil
29
+ ARGV.each_with_index do |a, i|
30
+ if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN
31
+ bundler_version = a
32
+ end
33
+ next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
34
+ bundler_version = $1 || ">= 0.a"
35
+ update_index = i
36
+ end
37
+ bundler_version
38
+ end
39
+
40
+ def gemfile
41
+ gemfile = ENV["BUNDLE_GEMFILE"]
42
+ return gemfile if gemfile && !gemfile.empty?
43
+
44
+ File.expand_path("../../Gemfile", __FILE__)
45
+ end
46
+
47
+ def lockfile
48
+ lockfile =
49
+ case File.basename(gemfile)
50
+ when "gems.rb" then gemfile.sub(/\.rb$/, gemfile)
51
+ else "#{gemfile}.lock"
52
+ end
53
+ File.expand_path(lockfile)
54
+ end
55
+
56
+ def lockfile_version
57
+ return unless File.file?(lockfile)
58
+ lockfile_contents = File.read(lockfile)
59
+ return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
60
+ Regexp.last_match(1)
61
+ end
62
+
63
+ def bundler_version
64
+ @bundler_version ||= begin
65
+ env_var_version || cli_arg_version ||
66
+ lockfile_version || "#{Gem::Requirement.default}.a"
67
+ end
68
+ end
69
+
70
+ def load_bundler!
71
+ ENV["BUNDLE_GEMFILE"] ||= gemfile
72
+
73
+ # must dup string for RG < 1.8 compatibility
74
+ activate_bundler(bundler_version.dup)
75
+ end
76
+
77
+ def activate_bundler(bundler_version)
78
+ if Gem::Version.correct?(bundler_version) && Gem::Version.new(bundler_version).release < Gem::Version.new("2.0")
79
+ bundler_version = "< 2"
80
+ end
81
+ gem_error = activation_error_handling do
82
+ gem "bundler", bundler_version
83
+ end
84
+ return if gem_error.nil?
85
+ require_error = activation_error_handling do
86
+ require "bundler/version"
87
+ end
88
+ return if require_error.nil? && Gem::Requirement.new(bundler_version).satisfied_by?(Gem::Version.new(Bundler::VERSION))
89
+ warn "Activating bundler (#{bundler_version}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_version}'`"
90
+ exit 42
91
+ end
92
+
93
+ def activation_error_handling
94
+ yield
95
+ nil
96
+ rescue StandardError, LoadError => e
97
+ e
98
+ end
99
+ end
100
+
101
+ m.load_bundler!
102
+
103
+ if m.invoked_as_script?
104
+ load Gem.bin_path("bundler", "bundle")
105
+ end
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ $: << "lib"
3
+ require "simple/immutable"
4
+
5
+ require "irb"
6
+ require "irb/completion"
7
+
8
+ IRB.start
@@ -0,0 +1 @@
1
+ require "simple/immutable"
@@ -0,0 +1,148 @@
1
+ module Simple
2
+ end
3
+
4
+ class Simple::Immutable
5
+ SELF = self
6
+
7
+ # turns an object, which can be a hash or array of hashes, arrays, and scalars
8
+ # into an object which you can use to access with dot methods.
9
+ def self.create(object, max_depth = 5)
10
+ case object
11
+ when Array
12
+ raise ArgumentError, "Object nested too deep (or inner loop?)" if max_depth < 0
13
+
14
+ object.map { |obj| create obj, max_depth - 1 }
15
+ when Hash
16
+ new(object)
17
+ else
18
+ object
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def initialize(hsh)
25
+ @hsh = hsh
26
+ end
27
+
28
+ def method_missing(sym, *args, &block)
29
+ if args.empty? && !block
30
+ begin
31
+ value = @hsh.fetch(sym.to_sym) { @hsh.fetch(sym.to_s) }
32
+ return SELF.create(value)
33
+ rescue KeyError
34
+ # STDERR.puts "Missing attribute #{sym} for Immutable w/#{@hsh.inspect}"
35
+ nil
36
+ end
37
+ end
38
+
39
+ super
40
+ end
41
+
42
+ public
43
+
44
+ def respond_to_missing?(method_name, include_private = false)
45
+ @hsh.key?(method_name.to_sym) ||
46
+ @hsh.key?(method_name.to_s) ||
47
+ super
48
+ end
49
+
50
+ def inspect
51
+ "<Immutable: #{@hsh.inspect}>"
52
+ end
53
+
54
+ def respond_to?(sym)
55
+ super || @hsh.key?(sym.to_s) || @hsh.key?(sym.to_sym)
56
+ end
57
+
58
+ def ==(other)
59
+ @hsh == other
60
+ end
61
+ end
62
+
63
+ if $PROGRAM_NAME == __FILE__
64
+
65
+ # rubocop:disable Metrics/AbcSize
66
+
67
+ require "test-unit"
68
+
69
+ class Simple::Immutable::TestCase < Test::Unit::TestCase
70
+ Immutable = ::Simple::Immutable
71
+
72
+ def hsh
73
+ {
74
+ a: "a-value",
75
+ "b": "b-value",
76
+ "child": {
77
+ name: "childname",
78
+ grandchild: {
79
+ name: "grandchildname"
80
+ }
81
+ },
82
+ "children": [
83
+ "anna",
84
+ "arthur",
85
+ {
86
+ action: {
87
+ keep_your_mouth_shut: true
88
+ }
89
+ }
90
+ ]
91
+ }
92
+ end
93
+
94
+ def immutable
95
+ Immutable.create hsh
96
+ end
97
+
98
+ def test_hash_access
99
+ assert_equal "a-value", immutable.a
100
+ assert_equal "b-value", immutable.b
101
+ end
102
+
103
+ def test_comparison
104
+ immutable = Immutable.create hsh
105
+
106
+ assert_equal immutable, hsh
107
+ assert_not_equal({}, immutable)
108
+ end
109
+
110
+ def test_child_access
111
+ child = immutable.child
112
+ assert_kind_of(Immutable, child)
113
+ assert_equal "childname", immutable.child.name
114
+ assert_equal "grandchildname", immutable.child.grandchild.name
115
+ end
116
+
117
+ def test_array_access
118
+ assert_kind_of(Array, immutable.children)
119
+ assert_equal 3, immutable.children.length
120
+ assert_equal "anna", immutable.children[0]
121
+
122
+ assert_kind_of(Immutable, immutable.children[2])
123
+ assert_equal true, immutable.children[2].action.keep_your_mouth_shut
124
+ end
125
+
126
+ def test_base_class
127
+ assert_nothing_raised do
128
+ immutable.object_id
129
+ end
130
+ end
131
+
132
+ def test_missing_keys
133
+ assert_raise(NoMethodError) do
134
+ immutable.foo
135
+ end
136
+ end
137
+
138
+ def test_skip_when_args_or_block
139
+ assert_raise(NoMethodError) do
140
+ immutable.a(1, 2, 3)
141
+ end
142
+ assert_raise(NoMethodError) do
143
+ immutable.a { :dummy }
144
+ end
145
+ end
146
+ end
147
+
148
+ end
@@ -0,0 +1,3 @@
1
+ #!/bin/bash
2
+
3
+ $0.rb "$@"
@@ -0,0 +1,94 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # -- helpers ------------------------------------------------------------------
4
+
5
+ def sys(cmd)
6
+ STDERR.puts "> #{cmd}"
7
+ system cmd
8
+ return true if $?.success?
9
+
10
+ STDERR.puts "> #{cmd} returned with exitstatus #{$?.exitstatus}"
11
+ $?.success?
12
+ end
13
+
14
+ def sys!(cmd, error: nil)
15
+ return true if sys(cmd)
16
+ STDERR.puts error if error
17
+ exit 1
18
+ end
19
+
20
+ def die!(msg)
21
+ STDERR.puts msg
22
+ exit 1
23
+ end
24
+
25
+ ROOT = File.expand_path("#{File.dirname(__FILE__)}/..")
26
+
27
+ GEMSPEC = Dir.glob("*.gemspec").first || die!("Missing gemspec file.")
28
+
29
+ # -- Version reading and bumping ----------------------------------------------
30
+
31
+ module Version
32
+ extend self
33
+
34
+ VERSION_FILE = "#{Dir.getwd}/VERSION"
35
+
36
+ def read_version
37
+ version = File.exist?(VERSION_FILE) ? File.read(VERSION_FILE) : "0.0.1"
38
+ version.chomp!
39
+ raise "Invalid version number in #{VERSION_FILE}" unless version =~ /^\d+\.\d+\.\d+$/
40
+ version
41
+ end
42
+
43
+ def auto_version_bump
44
+ old_version_number = read_version
45
+ old = old_version_number.split('.')
46
+
47
+ current = old[0..-2] << old[-1].next
48
+ current.join('.')
49
+ end
50
+
51
+ def bump_version
52
+ next_version = ENV["VERSION"] || auto_version_bump
53
+ File.open(VERSION_FILE, "w") { |io| io.write next_version }
54
+ end
55
+ end
56
+
57
+ # -- check, bump, release a new gem version -----------------------------------
58
+
59
+ Dir.chdir ROOT
60
+ $BASE_BRANCH = ENV['BRANCH'] || 'master'
61
+
62
+ # ENV["BUNDLE_GEMFILE"] = "#{Dir.getwd}/Gemfile"
63
+ # sys! "bundle install"
64
+
65
+ sys! "git diff --exit-code > /dev/null", error: 'There are unstaged changes in your working directory'
66
+ sys! "git diff --cached --exit-code > /dev/null", error: 'There are staged but uncommitted changes'
67
+
68
+ sys! "git checkout #{$BASE_BRANCH}"
69
+ sys! "git pull"
70
+
71
+ Version.bump_version
72
+ version = Version.read_version
73
+
74
+ sys! "git add VERSION"
75
+ sys! "git commit -m \"bump gem to v#{version}\""
76
+ sys! "git tag -a v#{version} -m \"Tag #{version}\""
77
+
78
+ sys! "git push origin #{$BASE_BRANCH}"
79
+ sys! 'git push --tags --force'
80
+
81
+ sys! "gem build #{GEMSPEC}"
82
+ sys! "mkdir -p pkg"
83
+ sys! "mv *.gem pkg"
84
+
85
+ gem_file = Dir.glob('pkg/*.gem').sort.last
86
+
87
+ sys! "gem install #{gem_file}"
88
+ sys! "gem push #{gem_file}"
89
+
90
+ STDERR.puts <<-MSG
91
+ ================================================================================
92
+ Thank you for releasing a new gem version. You made my day.
93
+ ================================================================================
94
+ MSG
@@ -0,0 +1,25 @@
1
+ # This file is part of the sinatra-sse ruby gem.
2
+ #
3
+ # Copyright (c) 2016, 2017 @radiospiel, mediapeers Gem
4
+ # Distributed under the terms of the modified BSD license, see LICENSE.BSD
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "simple-immutable"
8
+ gem.version = File.read "VERSION"
9
+
10
+ gem.authors = [ "radiospiel", "mediapeers GmbH" ]
11
+ gem.email = "eno@radiospiel.org"
12
+ gem.homepage = "http://github.com/radiospiel/simple-immutable"
13
+ gem.summary = "Immutable ruby objects"
14
+
15
+ gem.description = "Immutable ruby objects implementing dot and [] accessors."
16
+
17
+ gem.files = `git ls-files`.split($/)
18
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
+ gem.require_paths = %w(lib)
20
+
21
+ # executables are used for development purposes only
22
+ gem.executables = []
23
+
24
+ gem.required_ruby_version = '~> 2.3'
25
+ end
metadata ADDED
@@ -0,0 +1,55 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: simple-immutable
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - radiospiel
8
+ - mediapeers GmbH
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2020-03-03 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Immutable ruby objects implementing dot and [] accessors.
15
+ email: eno@radiospiel.org
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - ".gitignore"
21
+ - ".tm_properties"
22
+ - Gemfile
23
+ - Makefile
24
+ - README.md
25
+ - VERSION
26
+ - bin/bundle
27
+ - bin/console
28
+ - lib/simple-immutable.rb
29
+ - lib/simple/immutable.rb
30
+ - scripts/release
31
+ - scripts/release.rb
32
+ - simple-immutable.gemspec
33
+ homepage: http://github.com/radiospiel/simple-immutable
34
+ licenses: []
35
+ metadata: {}
36
+ post_install_message:
37
+ rdoc_options: []
38
+ require_paths:
39
+ - lib
40
+ required_ruby_version: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - "~>"
43
+ - !ruby/object:Gem::Version
44
+ version: '2.3'
45
+ required_rubygems_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '0'
50
+ requirements: []
51
+ rubygems_version: 3.0.6
52
+ signing_key:
53
+ specification_version: 4
54
+ summary: Immutable ruby objects
55
+ test_files: []