PackingPeanut 0.0.3 → 1.0.0
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/README.md +28 -15
- data/lib/{project → PackingPeanut-android}/PackingPeanut.rb +24 -12
- data/lib/PackingPeanut-ios/PackingPeanut.rb +68 -0
- data/lib/PackingPeanut-ios/ns_user_defaults.rb +15 -0
- data/lib/PackingPeanut.rb +26 -6
- metadata +36 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e2f04de5df63f75fb232e267e56ce3f33bc0eefb
|
4
|
+
data.tar.gz: 9ad3ba2c1db95ad649252daa5a85c7c786d12419
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6fc18eab2b1d752c17d3c8f78df711e4f53fe66ecdf8bb94940b457c8d8be0adbfe857eda9822b69b526857cc3d90c9b21f831e57bb46ea312b4a14b8812c001
|
7
|
+
data.tar.gz: b752f132729c59c907d92b1f075bcff4aee493cfe8a35b519303c3a59c190612f2cfc3650204602209d777faec73722f181c04cb29c567e8e9129468d23c76a3
|
data/README.md
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
#  PackingPeanut [](http://badge.fury.io/rb/PackingPeanut)
|
2
2
|
|
3
|
-
|
3
|
+
### Cross Platform App Persistence
|
4
|
+

|
4
5
|
|
5
|
-
|
6
|
+
Inspired by BubbleWrap's easy syntax for App Persistence - Now a CROSS PLATFORM App Persistence Gem for RubyMotion.
|
7
|
+
|
8
|
+
There is a sedulous effort to make this syntax fit BubbleWrap's as much as possible for easy replacement :smiling_imp:
|
6
9
|
|
7
10
|
[**GITHUB HOMEPAGE**](http://gantman.github.io/PackingPeanut/)
|
8
11
|
|
@@ -16,6 +19,10 @@ There is a sedulous effort to make this syntax fit BubbleWrap's as much as possi
|
|
16
19
|
|
17
20
|
$ bundle
|
18
21
|
|
22
|
+
**Step 3:** IF on Android:
|
23
|
+
|
24
|
+
$ [bundle exec] rake gradle:install
|
25
|
+
|
19
26
|
## Usage
|
20
27
|
|
21
28
|
**It's as simple as:**
|
@@ -26,32 +33,34 @@ App::Persistence[:foo] = true
|
|
26
33
|
|
27
34
|
Whirlwind Tour via the REPL
|
28
35
|
```
|
29
|
-
#
|
30
|
-
#
|
36
|
+
# ONLY ANDROID REQUIRES CONTEXT!
|
37
|
+
# Set the context (required in the REPL or when not including the module).
|
31
38
|
$ App::Persistence.context = self
|
32
39
|
=> #<MainActivity:0x1d20058e>
|
33
40
|
$ App::Persistence['dinner'] = "nachos"
|
34
|
-
=>
|
35
|
-
$ App::Persistence['dinner']
|
41
|
+
=> "nachos"
|
42
|
+
$ App::Persistence['dinner']
|
36
43
|
=> "nachos"
|
37
44
|
$ App::Persistence[:lunch] = "tacos"
|
38
45
|
=> "tacos" # Use symbols or strings as you please
|
39
46
|
$ App::Persistence.all
|
40
|
-
=>
|
47
|
+
=> {"dinner"=>"nachos", "lunch"=>"tacos"}
|
41
48
|
$ App::Persistence.storage_file = "some_new_file"
|
42
49
|
=> "some_new_file"
|
43
50
|
$ App::Persistence['dinner']
|
44
51
|
=> "" # empty because we're now outside the default storage file.
|
45
|
-
$ App::Persistence.preference_mode = :world_readable
|
46
|
-
=> :world_redable
|
47
|
-
$ PP::Persistence['some_boolean'] = true #You can use PP instead of App if you like
|
48
|
-
```
|
49
52
|
|
53
|
+
# You can use PP instead of App::Persistence if you like
|
54
|
+
$ PP['some_boolean'] = true
|
50
55
|
|
56
|
+
# On Android you can set prefrence_modes for cross/app communication
|
57
|
+
$ App::Persistence.preference_mode = :world_readable
|
58
|
+
=> :world_readable
|
59
|
+
```
|
51
60
|
|
52
61
|
## What are preference modes?
|
53
62
|
|
54
|
-
Preference Modes are
|
63
|
+
Preference Modes are Android Operating modes, used to control permission levels on the persistence file.
|
55
64
|
|
56
65
|
Memorizable symbols and their corresponding constants:
|
57
66
|
```ruby
|
@@ -66,11 +75,15 @@ Memorizable symbols and their corresponding constants:
|
|
66
75
|
}
|
67
76
|
```
|
68
77
|
|
69
|
-
|
70
|
-
|
78
|
+
Use 0 or MODE_PRIVATE for the default operation, MODE_WORLD_READABLE and MODE_WORLD_WRITEABLE for more permissive modes. The bit MODE_MULTI_PROCESS can also be used if multiple processes are mutating the same SharedPreferences file. MODE_MULTI_PROCESS is always on in apps targeting Gingerbread (Android 2.3) and below, and off by default in later versions.
|
79
|
+
|
80
|
+
## Dependencies
|
81
|
+
Adding [Darin's moran gem](https://github.com/darinwilson/moran) allowed serialization of hashes for Android. This means `motion-gradle` is also necessary for complete Packing Peanut excellence on Android.
|
71
82
|
|
72
83
|
## Tests?
|
73
|
-
|
84
|
+
|
85
|
+
* **iOS:** Yup!
|
86
|
+
* **Android:** Boy that would be nice wouldn't it?
|
74
87
|
|
75
88
|
## Contributing
|
76
89
|
|
@@ -23,27 +23,29 @@ module App
|
|
23
23
|
# Serialize key/value as json then
|
24
24
|
# store that string with the settings key == json key
|
25
25
|
def []=(key, value)
|
26
|
+
# Let's play nice with strings and non-strings
|
27
|
+
string_key = key.to_s
|
26
28
|
settings = get_settings
|
27
29
|
editor = settings.edit
|
28
|
-
json = serialize(
|
29
|
-
editor.putString(
|
30
|
-
editor.commit
|
30
|
+
json = serialize(string_key,value)
|
31
|
+
editor.putString(string_key, json.toString)
|
32
|
+
editor.commit
|
31
33
|
end
|
32
34
|
|
33
35
|
def [](key)
|
34
|
-
|
36
|
+
# Let's play nice with strings and non-strings
|
37
|
+
string_key = key.to_s
|
38
|
+
json_string = get_value(string_key)
|
35
39
|
return json_string if json_string == ""
|
36
|
-
deserialize(
|
40
|
+
deserialize(string_key, json_string)
|
37
41
|
end
|
38
42
|
|
39
43
|
def serialize(key, value)
|
40
|
-
|
41
|
-
json.put(key, value)
|
44
|
+
Moran.generate({:"#{key}" => value})
|
42
45
|
end
|
43
46
|
|
44
47
|
def deserialize(key, json_string)
|
45
|
-
|
46
|
-
json.get(key)
|
48
|
+
Moran.parse(json_string)[key]
|
47
49
|
end
|
48
50
|
|
49
51
|
def get_value key
|
@@ -69,7 +71,15 @@ module App
|
|
69
71
|
|
70
72
|
def all
|
71
73
|
settings = get_settings
|
72
|
-
settings.getAll.map { |key, value|
|
74
|
+
all_hashes = settings.getAll.map { |key, value| Moran.parse(value) }
|
75
|
+
|
76
|
+
# Currently an array of hashes, needs to be one big hash
|
77
|
+
merged_hashes = {}
|
78
|
+
all_hashes.each do |h|
|
79
|
+
merged_hashes = merged_hashes.merge(h)
|
80
|
+
end
|
81
|
+
|
82
|
+
merged_hashes
|
73
83
|
end
|
74
84
|
|
75
85
|
def get_settings
|
@@ -79,15 +89,17 @@ module App
|
|
79
89
|
# Allows us to use this from anywhere by setting the context
|
80
90
|
# Useful when you want to access this module from the REPL
|
81
91
|
def current_context
|
92
|
+
#p defined? getApplicationContext
|
82
93
|
@context || getApplicationContext
|
83
94
|
end
|
84
95
|
|
85
96
|
# attr_accessor is not supported for modules in RMAndroid... yet.
|
86
|
-
def context= supplied_context
|
97
|
+
def context= supplied_context
|
87
98
|
@context = supplied_context
|
88
99
|
end
|
89
100
|
|
90
101
|
end
|
91
102
|
end
|
92
103
|
|
93
|
-
|
104
|
+
# delicious shortcut
|
105
|
+
PP = App::Persistence unless defined? PP
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# Persistence module built on top of NSUserDefaults
|
2
|
+
module App
|
3
|
+
module Persistence
|
4
|
+
module_function
|
5
|
+
|
6
|
+
def app_key
|
7
|
+
@app_key ||= NSBundle.mainBundle.bundleIdentifier
|
8
|
+
end
|
9
|
+
|
10
|
+
def storage_file
|
11
|
+
@persistence_storage_file ||= "default_persistence_file"
|
12
|
+
end
|
13
|
+
|
14
|
+
def storage_file=(value)
|
15
|
+
@persistence_storage_file = value
|
16
|
+
end
|
17
|
+
|
18
|
+
def []=(key, value)
|
19
|
+
storage.setObject(value, forKey: storage_key(key))
|
20
|
+
storage.synchronize
|
21
|
+
end
|
22
|
+
|
23
|
+
def [](key)
|
24
|
+
value = storage.objectForKey storage_key(key)
|
25
|
+
|
26
|
+
# RubyMotion currently has a bug where the strings returned from
|
27
|
+
# standardUserDefaults are missing some methods (e.g. to_data).
|
28
|
+
# And because the returned object is slightly different than a normal
|
29
|
+
# String, we can't just use `value.is_a?(String)`
|
30
|
+
value.class.to_s == 'String' ? value.dup : value
|
31
|
+
end
|
32
|
+
|
33
|
+
def merge(values)
|
34
|
+
values.each do |key, value|
|
35
|
+
storage.setObject(value, forKey: storage_key(key))
|
36
|
+
end
|
37
|
+
storage.synchronize
|
38
|
+
end
|
39
|
+
|
40
|
+
def delete(key)
|
41
|
+
value = storage.objectForKey storage_key(key)
|
42
|
+
storage.removeObjectForKey(storage_key(key))
|
43
|
+
storage.synchronize
|
44
|
+
value
|
45
|
+
end
|
46
|
+
|
47
|
+
def storage
|
48
|
+
NSUserDefaults.standardUserDefaults
|
49
|
+
end
|
50
|
+
|
51
|
+
def storage_key(key)
|
52
|
+
"#{app_key}_#{storage_file}_#{key}"
|
53
|
+
end
|
54
|
+
|
55
|
+
def all
|
56
|
+
hash = storage.dictionaryRepresentation.select{|k,v| k.start_with?("#{app_key}_#{storage_file}") }
|
57
|
+
new_hash = {}
|
58
|
+
hash.each do |k,v|
|
59
|
+
new_hash[k.sub("#{app_key}_#{storage_file}_", '')] = v
|
60
|
+
end
|
61
|
+
new_hash
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
# delicious shortcut
|
68
|
+
PP = App::Persistence unless defined? PP
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# Reopens the NSUserDefaults class to add Array like accessors
|
2
|
+
# @see https://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/nsuserdefaults_Class/Reference/Reference.html
|
3
|
+
class NSUserDefaults
|
4
|
+
|
5
|
+
# Retrieves the object for the passed key
|
6
|
+
def [](key)
|
7
|
+
self.objectForKey(key.to_s)
|
8
|
+
end
|
9
|
+
|
10
|
+
# Sets the value for a given key and save it right away.
|
11
|
+
def []=(key, val)
|
12
|
+
self.setObject(val, forKey: key.to_s)
|
13
|
+
self.synchronize
|
14
|
+
end
|
15
|
+
end
|
data/lib/PackingPeanut.rb
CHANGED
@@ -1,12 +1,32 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
|
3
2
|
unless defined?(Motion::Project::Config)
|
4
|
-
raise "
|
3
|
+
raise "The PackingPeanut gem must be required within a RubyMotion project Rakefile."
|
4
|
+
end
|
5
|
+
|
6
|
+
# WHAT ARE WE?
|
7
|
+
platform = Motion::Project::App.respond_to?(:template) ? Motion::Project::App.template : :ios
|
8
|
+
if platform.to_s.start_with?('ios')
|
9
|
+
platform_name = 'ios'
|
10
|
+
elsif platform.to_s.start_with?('android')
|
11
|
+
platform_name = 'android'
|
5
12
|
end
|
6
13
|
|
7
|
-
|
14
|
+
# necessary for Android gem dependency as of 5/9/2015
|
15
|
+
require "moran" if platform_name == "android"
|
16
|
+
|
8
17
|
Motion::Project::App.setup do |app|
|
9
|
-
|
10
|
-
|
11
|
-
|
18
|
+
platform_lib = File.join(File.dirname(__FILE__), "PackingPeanut-#{platform_name}")
|
19
|
+
unless File.exists? platform_lib
|
20
|
+
raise "Sorry, the platform #{platform.inspect} (aka #{platform_name}) is not supported by PackingPeanut"
|
21
|
+
end
|
22
|
+
|
23
|
+
# scans app.files until it finds app/ (the default)
|
24
|
+
# if found, it inserts just before those files, otherwise it will insert to
|
25
|
+
# the end of the list
|
26
|
+
insert_point = app.files.find_index { |file| file =~ /^(?:\.\/)?app\// } || 0
|
27
|
+
|
28
|
+
Dir.glob(File.join(platform_lib, '**/*.rb')).reverse.each do |file|
|
29
|
+
app.files.insert(insert_point, file)
|
30
|
+
end
|
31
|
+
|
12
32
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: PackingPeanut
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gant
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-05-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -24,7 +24,35 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
-
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: moran
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: motion-gradle
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: App persistent data for RubyMotion Android and iOS
|
28
56
|
email:
|
29
57
|
- GantMan@gmail.com
|
30
58
|
executables: []
|
@@ -32,8 +60,10 @@ extensions: []
|
|
32
60
|
extra_rdoc_files: []
|
33
61
|
files:
|
34
62
|
- README.md
|
63
|
+
- lib/PackingPeanut-android/PackingPeanut.rb
|
64
|
+
- lib/PackingPeanut-ios/PackingPeanut.rb
|
65
|
+
- lib/PackingPeanut-ios/ns_user_defaults.rb
|
35
66
|
- lib/PackingPeanut.rb
|
36
|
-
- lib/project/PackingPeanut.rb
|
37
67
|
homepage: http://gantman.github.io/PackingPeanut/
|
38
68
|
licenses:
|
39
69
|
- MIT
|
@@ -57,6 +87,6 @@ rubyforge_project:
|
|
57
87
|
rubygems_version: 2.4.5
|
58
88
|
signing_key:
|
59
89
|
specification_version: 4
|
60
|
-
summary: App persistent data for RubyMotion Android, designed to fit the API
|
61
|
-
of the popular iOS Gem BubbleWrap which also supplies persistence.
|
90
|
+
summary: App persistent data for RubyMotion Android and iOS, designed to fit the API
|
91
|
+
stylings of the popular iOS Gem BubbleWrap which also supplies persistence.
|
62
92
|
test_files: []
|