nori 2.6.0 → 2.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.devcontainer/devcontainer.json +19 -0
- data/.github/dependabot.yml +12 -0
- data/.github/workflows/test.yml +26 -0
- data/CHANGELOG.md +25 -0
- data/Gemfile +2 -5
- data/README.md +69 -47
- data/lib/nori/core_ext/hash.rb +1 -1
- data/lib/nori/core_ext.rb +1 -2
- data/lib/nori/parser/rexml.rb +6 -3
- data/lib/nori/string_utils.rb +18 -0
- data/lib/nori/version.rb +1 -1
- data/lib/nori.rb +20 -1
- data/nori.gemspec +7 -4
- data/spec/nori/api_spec.rb +3 -10
- data/spec/nori/nori_spec.rb +7 -2
- data/spec/nori/string_utils_spec.rb +33 -0
- metadata +30 -22
- data/.travis.yml +0 -11
- data/lib/nori/core_ext/object.rb +0 -13
- data/lib/nori/core_ext/string.rb +0 -21
- data/spec/nori/core_ext/object_spec.rb +0 -19
- data/spec/nori/core_ext/string_spec.rb +0 -33
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e562b494afc72df387f136e51af0c5e0445b528b5515eedad7f60b3d49d207a5
|
4
|
+
data.tar.gz: 5eabad83b50392e39973058c70d6307ddaaeea47934c292fbd472ee0f93680f9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6366a2ac0d9dd99e4fd7b0f32d95dfb21f76885ab18fc7f3f7767c5e257b61e3817d2bf13f9a113feb2482fdb6f5a912956ef5d17a3f868a9139e9b55683402f
|
7
|
+
data.tar.gz: cf295850b06961ed67644a8c06c61152cecf5c8512f8a74a03115e47fe8f9a567300d9af8d91504013777400882869cb7016c80563015e6423e86718c7b828bd
|
@@ -0,0 +1,19 @@
|
|
1
|
+
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
2
|
+
// README at: https://github.com/devcontainers/templates/tree/main/src/ruby
|
3
|
+
{
|
4
|
+
"name": "Ruby",
|
5
|
+
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
6
|
+
"image": "mcr.microsoft.com/devcontainers/ruby:0-3-bullseye"
|
7
|
+
|
8
|
+
// Features to add to the dev container. More info: https://containers.dev/features.
|
9
|
+
// "features": {},
|
10
|
+
|
11
|
+
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
12
|
+
// "forwardPorts": [],
|
13
|
+
|
14
|
+
// Configure tool-specific properties.
|
15
|
+
// "customizations": {},
|
16
|
+
|
17
|
+
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
18
|
+
// "remoteUser": "root"
|
19
|
+
}
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# To get started with Dependabot version updates, you'll need to specify which
|
2
|
+
# package ecosystems to update and where the package manifests are located.
|
3
|
+
# Please see the documentation for more information:
|
4
|
+
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
5
|
+
# https://containers.dev/guide/dependabot
|
6
|
+
|
7
|
+
version: 2
|
8
|
+
updates:
|
9
|
+
- package-ecosystem: "devcontainers"
|
10
|
+
directory: "/"
|
11
|
+
schedule:
|
12
|
+
interval: weekly
|
@@ -0,0 +1,26 @@
|
|
1
|
+
name: CI
|
2
|
+
|
3
|
+
on: [push, pull_request]
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
build:
|
7
|
+
runs-on: ubuntu-latest
|
8
|
+
|
9
|
+
strategy:
|
10
|
+
matrix:
|
11
|
+
ruby-version:
|
12
|
+
- '3.0'
|
13
|
+
- '3.1'
|
14
|
+
- '3.2'
|
15
|
+
- '3.3'
|
16
|
+
- 'head'
|
17
|
+
- jruby-9.4.5.0
|
18
|
+
steps:
|
19
|
+
- uses: actions/checkout@v4
|
20
|
+
- name: Set up Ruby ${{ matrix.ruby-version }}
|
21
|
+
uses: ruby/setup-ruby@v1
|
22
|
+
with:
|
23
|
+
ruby-version: ${{ matrix.ruby-version }}
|
24
|
+
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
25
|
+
- name: Run tests
|
26
|
+
run: bundle exec rake
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
# 2.7.1 (2024-07-28)
|
2
|
+
|
3
|
+
* Stop monkey-patching String with #snakecase by @mchu in https://github.com/savonrb/nori/pull/102
|
4
|
+
|
5
|
+
# 2.7.0 (2024-02-13)
|
6
|
+
|
7
|
+
* Added support for ruby 3.1, 3.2, 3.3. Dropped support for ruby 2.7 and below.
|
8
|
+
* Feature: `Nori::Parser` has a new option, `:scrub_xml`, which defaults to true, for scrubbing invalid characters ([#72](https://github.com/savonrb/nori/pull/72)). This should allow documents containing invalid characters to still be parsed.
|
9
|
+
* Fix: REXML parser changes `<` inside CDATA to `<` ([#94](https://github.com/savonrb/nori/pull/94))
|
10
|
+
* Change: `Object#blank?` is no longer patched in.
|
11
|
+
|
1
12
|
# 2.6.0 (2015-05-06)
|
2
13
|
|
3
14
|
* Feature: [#69](https://github.com/savonrb/nori/pull/69) Add option to convert empty tags to a value other than nil.
|
@@ -5,6 +16,20 @@
|
|
5
16
|
# 2.5.0 (2015-03-31)
|
6
17
|
|
7
18
|
* Formally drop support for ruby 1.8.7. Installing Nori from rubygems for that version should no longer attempt to install versions that will not work.
|
19
|
+
* BREAKING CHANGE: Newlines are now preserved when present in the value of inner text nodes. See the example below:
|
20
|
+
|
21
|
+
before:
|
22
|
+
|
23
|
+
```
|
24
|
+
Nori.new.parse("<outer>\n<embedded>\n<one></one>\n<two></two>\n<embedded>\n</outer>")
|
25
|
+
=> {"outer"=>"<embedded><one></one><two></two><embedded>"}
|
26
|
+
```
|
27
|
+
|
28
|
+
after:
|
29
|
+
```
|
30
|
+
Nori.new.parse("<outer>\n<embedded>\n<one></one>\n<two></two>\n<embedded>\n</outer>")
|
31
|
+
=> {"outer"=>"<embedded>\n<one></one>\n<two></two>\n<embedded>\n"}
|
32
|
+
```
|
8
33
|
|
9
34
|
# 2.4.0 (2014-04-19)
|
10
35
|
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,21 +1,11 @@
|
|
1
1
|
Nori
|
2
2
|
====
|
3
3
|
|
4
|
-
[![
|
5
|
-
[![Gem Version](https://badge.fury.io/rb/nori.
|
6
|
-
[![Code Climate](https://codeclimate.com/github/savonrb/nori.
|
7
|
-
[![Coverage Status](https://coveralls.io/repos/savonrb/nori/badge.png?branch=master)](https://coveralls.io/r/savonrb/nori)
|
4
|
+
[![CI](https://github.com/savonrb/nori/actions/workflows/test.yml/badge.svg)](https://github.com/savonrb/nori/actions/workflows/test.yml)
|
5
|
+
[![Gem Version](https://badge.fury.io/rb/nori.svg)](http://badge.fury.io/rb/nori)
|
6
|
+
[![Code Climate](https://codeclimate.com/github/savonrb/nori.svg)](https://codeclimate.com/github/savonrb/nori)
|
8
7
|
|
9
|
-
|
10
|
-
Really simple XML parsing ripped from Crack which ripped it from Merb.
|
11
|
-
Nori was created to bypass the stale development of Crack, improve its XML parser
|
12
|
-
and fix certain issues.
|
13
|
-
|
14
|
-
``` ruby
|
15
|
-
parser = Nori.new
|
16
|
-
parser.parse("<tag>This is the contents</tag>")
|
17
|
-
# => { 'tag' => 'This is the contents' }
|
18
|
-
```
|
8
|
+
Really simple XML parsing ripped from Crack, which ripped it from Merb.
|
19
9
|
|
20
10
|
Nori supports pluggable parsers and ships with both REXML and Nokogiri implementations.
|
21
11
|
It defaults to Nokogiri since v2.0.0, but you can change it to use REXML via:
|
@@ -24,64 +14,96 @@ It defaults to Nokogiri since v2.0.0, but you can change it to use REXML via:
|
|
24
14
|
Nori.new(:parser => :rexml) # or :nokogiri
|
25
15
|
```
|
26
16
|
|
27
|
-
Make sure Nokogiri is in your LOAD_PATH when parsing XML, because Nori tries to load it
|
28
|
-
when it's needed.
|
17
|
+
Make sure Nokogiri is in your LOAD_PATH when parsing XML, because Nori tries to load it when it's needed.
|
29
18
|
|
19
|
+
# Examples
|
30
20
|
|
31
|
-
|
32
|
-
|
21
|
+
```ruby
|
22
|
+
Nori.new.parse("<tag>This is the content</tag>")
|
23
|
+
# => {"tag"=>"This is the content"}
|
33
24
|
|
34
|
-
|
25
|
+
Nori.new.parse('<foo />')
|
26
|
+
#=> {"foo"=>nil}
|
35
27
|
|
36
|
-
|
37
|
-
|
38
|
-
to `Time`, `Date` and `DateTime` objects.
|
28
|
+
Nori.new.parse('<foo bar />')
|
29
|
+
#=> {}
|
39
30
|
|
40
|
-
|
31
|
+
Nori.new.parse('<foo bar="baz"/>')
|
32
|
+
#=> {"foo"=>{"@bar"=>"baz"}}
|
41
33
|
|
42
|
-
|
43
|
-
|
34
|
+
Nori.new.parse('<foo bar="baz">Content</foo>')
|
35
|
+
#=> {"foo"=>"Content"}
|
44
36
|
```
|
45
37
|
|
38
|
+
## Nori::StringWithAttributes
|
46
39
|
|
47
|
-
|
48
|
-
----------
|
40
|
+
You can access a string node's attributes via `attributes`.
|
49
41
|
|
50
|
-
|
51
|
-
|
42
|
+
```ruby
|
43
|
+
result = Nori.new.parse('<foo bar="baz">Content</foo>')
|
44
|
+
#=> {"foo"=>"Content"}
|
52
45
|
|
53
|
-
|
54
|
-
|
46
|
+
result["foo"].class
|
47
|
+
# => Nori::StringWithAttributes
|
48
|
+
|
49
|
+
result["foo"].attributes
|
50
|
+
# => {"bar"=>"baz"}
|
55
51
|
```
|
56
52
|
|
53
|
+
## advanced_typecasting
|
57
54
|
|
58
|
-
|
59
|
-
|
55
|
+
Nori can automatically convert string values to `TrueClass`, `FalseClass`, `Time`, `Date`, and `DateTime`:
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
# "true" and "false" String values are converted to `TrueClass` and `FalseClass`.
|
59
|
+
Nori.new.parse("<value>true</value>")
|
60
|
+
# => {"value"=>true}
|
60
61
|
|
61
|
-
|
62
|
-
|
62
|
+
# String values matching xs:time, xs:date and xs:dateTime are converted to `Time`, `Date` and `DateTime` objects.
|
63
|
+
Nori.new.parse("<value>09:33:55.7Z</value>")
|
64
|
+
# => {"value"=>2022-09-29 09:33:55.7 UTC
|
65
|
+
|
66
|
+
# disable with advanced_typecasting: false
|
67
|
+
Nori.new(advanced_typecasting: false).parse("<value>true</value>")
|
68
|
+
# => {"value"=>"true"}
|
69
|
+
|
70
|
+
```
|
71
|
+
|
72
|
+
## strip_namespaces
|
73
|
+
|
74
|
+
Nori can strip the namespaces from your XML tags. This feature is disabled by default.
|
63
75
|
|
64
76
|
``` ruby
|
65
|
-
|
77
|
+
Nori.new.parse('<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"></soap:Envelope>')
|
78
|
+
# => {"soap:Envelope"=>{"@xmlns:soap"=>"http://schemas.xmlsoap.org/soap/envelope/"}}
|
66
79
|
|
67
|
-
|
68
|
-
|
80
|
+
Nori.new(:strip_namespaces => true).parse('<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"></soap:Envelope>')
|
81
|
+
# => {"Envelope"=>{"@xmlns:soap"=>"http://schemas.xmlsoap.org/soap/envelope/"}}
|
69
82
|
```
|
70
83
|
|
71
|
-
|
72
|
-
----------------------
|
84
|
+
## convert_tags_to
|
73
85
|
|
74
|
-
Nori
|
75
|
-
For example:
|
86
|
+
Nori lets you specify a custom formula to convert XML tags to Hash keys using `convert_tags_to`.
|
76
87
|
|
77
|
-
```ruby
|
78
|
-
|
79
|
-
|
88
|
+
``` ruby
|
89
|
+
Nori.new.parse('<userResponse><accountStatus>active</accountStatus></userResponse>')
|
90
|
+
# => {"userResponse"=>{"accountStatus"=>"active"}}
|
91
|
+
|
92
|
+
parser = Nori.new(:convert_tags_to => lambda { |tag| Nori::StringUtils.snakecase(tag).to_sym })
|
93
|
+
parser.parse('<userResponse><accountStatus>active</accountStatus></userResponse>')
|
94
|
+
# => {:user_response=>{:account_status=>"active"}}
|
80
95
|
```
|
81
96
|
|
82
|
-
|
97
|
+
## convert_dashes_to_underscores
|
98
|
+
|
99
|
+
By default, Nori will automatically convert dashes in tag names to underscores.
|
83
100
|
|
84
101
|
```ruby
|
102
|
+
Nori.new.parse('<any-tag>foo bar</any-tag>')
|
103
|
+
# => {"any_tag"=>"foo bar"}
|
104
|
+
|
105
|
+
# disable with convert_dashes_to_underscores
|
85
106
|
parser = Nori.new(:convert_dashes_to_underscores => false)
|
86
|
-
parser.parse('<any-tag>foo bar</any-tag>')
|
107
|
+
parser.parse('<any-tag>foo bar</any-tag>')
|
108
|
+
# => {"any-tag"=>"foo bar"}
|
87
109
|
```
|
data/lib/nori/core_ext/hash.rb
CHANGED
data/lib/nori/core_ext.rb
CHANGED
data/lib/nori/parser/rexml.rb
CHANGED
@@ -15,7 +15,8 @@ class Nori
|
|
15
15
|
parser = ::REXML::Parsers::BaseParser.new(xml)
|
16
16
|
|
17
17
|
while true
|
18
|
-
|
18
|
+
raw_data = parser.pull
|
19
|
+
event = unnormalize(raw_data)
|
19
20
|
case event[0]
|
20
21
|
when :end_document
|
21
22
|
break
|
@@ -28,15 +29,17 @@ class Nori
|
|
28
29
|
temp = stack.pop
|
29
30
|
stack.last.add_node(temp)
|
30
31
|
end
|
31
|
-
when :text
|
32
|
+
when :text
|
32
33
|
stack.last.add_node(event[1]) unless event[1].strip.length == 0 || stack.empty?
|
34
|
+
when :cdata
|
35
|
+
stack.last.add_node(raw_data[1]) unless raw_data[1].strip.length == 0 || stack.empty?
|
33
36
|
end
|
34
37
|
end
|
35
38
|
stack.length > 0 ? stack.pop.to_hash : {}
|
36
39
|
end
|
37
40
|
|
38
41
|
def self.unnormalize(event)
|
39
|
-
event.map
|
42
|
+
event.map do |el|
|
40
43
|
if el.is_a?(String)
|
41
44
|
::REXML::Text.unnormalize(el)
|
42
45
|
elsif el.is_a?(Hash)
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class Nori
|
2
|
+
module StringUtils
|
3
|
+
# Converts a string to snake case.
|
4
|
+
#
|
5
|
+
# @param inputstring [String] The string to be converted to snake case.
|
6
|
+
# @return [String] A copy of the input string converted to snake case.
|
7
|
+
def self.snakecase(inputstring)
|
8
|
+
str = inputstring.dup
|
9
|
+
str.gsub!(/::/, '/')
|
10
|
+
str.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
11
|
+
str.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
|
12
|
+
str.tr!(".", "_")
|
13
|
+
str.tr!("-", "_")
|
14
|
+
str.downcase!
|
15
|
+
str
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/nori/version.rb
CHANGED
data/lib/nori.rb
CHANGED
@@ -22,6 +22,7 @@ class Nori
|
|
22
22
|
:empty_tag_value => nil,
|
23
23
|
:advanced_typecasting => true,
|
24
24
|
:convert_dashes_to_underscores => true,
|
25
|
+
:scrub_xml => true,
|
25
26
|
:parser => :nokogiri
|
26
27
|
}
|
27
28
|
|
@@ -40,7 +41,7 @@ class Nori
|
|
40
41
|
end
|
41
42
|
|
42
43
|
def parse(xml)
|
43
|
-
cleaned_xml = xml.strip
|
44
|
+
cleaned_xml = scrub_xml(xml).strip
|
44
45
|
return {} if cleaned_xml.empty?
|
45
46
|
|
46
47
|
parser = load_parser @options[:parser]
|
@@ -77,4 +78,22 @@ class Nori
|
|
77
78
|
nil
|
78
79
|
end
|
79
80
|
|
81
|
+
def scrub_xml(string)
|
82
|
+
if @options[:scrub_xml]
|
83
|
+
if string.respond_to? :scrub
|
84
|
+
string.scrub
|
85
|
+
else
|
86
|
+
if string.valid_encoding?
|
87
|
+
string
|
88
|
+
else
|
89
|
+
enc = string.encoding
|
90
|
+
mid_enc = (["UTF-8", "UTF-16BE"].map { |e| Encoding.find(e) } - [enc]).first
|
91
|
+
string.encode(mid_enc, undef: :replace, invalid: :replace).encode(enc)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
else
|
95
|
+
string
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
80
99
|
end
|
data/nori.gemspec
CHANGED
@@ -10,14 +10,17 @@ Gem::Specification.new do |s|
|
|
10
10
|
s.homepage = "https://github.com/savonrb/nori"
|
11
11
|
s.summary = "XML to Hash translator"
|
12
12
|
s.description = s.summary
|
13
|
-
s.required_ruby_version = '>=
|
13
|
+
s.required_ruby_version = '>= 3.0'
|
14
14
|
|
15
|
-
s.rubyforge_project = "nori"
|
16
15
|
s.license = "MIT"
|
17
16
|
|
18
|
-
s.
|
17
|
+
s.add_dependency "bigdecimal"
|
18
|
+
|
19
|
+
s.add_development_dependency "rake", "~> 12.3.3"
|
19
20
|
s.add_development_dependency "nokogiri", ">= 1.4.0"
|
20
|
-
s.add_development_dependency "rspec", "~>
|
21
|
+
s.add_development_dependency "rspec", "~> 3.11.0"
|
22
|
+
|
23
|
+
s.metadata["rubygems_mfa_required"] = "true"
|
21
24
|
|
22
25
|
s.files = `git ls-files`.split("\n")
|
23
26
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
data/spec/nori/api_spec.rb
CHANGED
@@ -55,7 +55,7 @@ describe Nori do
|
|
55
55
|
it "converts all tags by a given formula" do
|
56
56
|
xml = '<userResponse id="1"><accountStatus>active</accountStatus></userResponse>'
|
57
57
|
|
58
|
-
snakecase_symbols = lambda { |tag|
|
58
|
+
snakecase_symbols = lambda { |tag| Nori::StringUtils.snakecase(tag).to_sym }
|
59
59
|
nori = nori(:convert_tags_to => snakecase_symbols)
|
60
60
|
|
61
61
|
expect(nori.parse(xml)).to eq({ :user_response => { :@id => "1", :account_status => "active" } })
|
@@ -108,13 +108,6 @@ describe Nori do
|
|
108
108
|
expect(Nori::Parser::Nokogiri).to receive(:parse).and_return({})
|
109
109
|
nori.parse("<any>thing</any>")
|
110
110
|
end
|
111
|
-
|
112
|
-
it "strips the XML" do
|
113
|
-
xml = double("xml")
|
114
|
-
expect(xml).to receive(:strip).and_return("<any>thing</any>")
|
115
|
-
|
116
|
-
expect(nori.parse(xml)).to eq({ "any" => "thing" })
|
117
|
-
end
|
118
111
|
end
|
119
112
|
|
120
113
|
context "#parse without :advanced_typecasting" do
|
@@ -163,8 +156,8 @@ describe Nori do
|
|
163
156
|
end
|
164
157
|
|
165
158
|
context "#parse with :convert_dashes_to_underscores" do
|
166
|
-
it "can be configured to skip dash to
|
167
|
-
xml = '<any-tag>foo bar</any-tag'
|
159
|
+
it "can be configured to skip dash to underscore conversion" do
|
160
|
+
xml = '<any-tag>foo bar</any-tag>'
|
168
161
|
hash = nori(:convert_dashes_to_underscores => false).parse(xml)
|
169
162
|
expect(hash).to eq({'any-tag' => 'foo bar'})
|
170
163
|
end
|
data/spec/nori/nori_spec.rb
CHANGED
@@ -21,11 +21,16 @@ describe Nori do
|
|
21
21
|
xml = <<-END
|
22
22
|
<tag>
|
23
23
|
<![CDATA[
|
24
|
-
text inside cdata
|
24
|
+
text inside cdata < test
|
25
25
|
]]>
|
26
26
|
</tag>
|
27
27
|
END
|
28
|
-
expect(parse(xml)["tag"].strip).to eq("text inside cdata")
|
28
|
+
expect(parse(xml)["tag"].strip).to eq("text inside cdata < test")
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should scrub bad characters" do
|
32
|
+
xml = "<tag>a\xfbc</tag>".force_encoding('UTF-8')
|
33
|
+
expect(parse(xml)["tag"]).to eq("a\uFFFDc")
|
29
34
|
end
|
30
35
|
|
31
36
|
it "should transform a simple tag with attributes" do
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Nori::StringUtils do
|
4
|
+
|
5
|
+
describe ".snakecase" do
|
6
|
+
it "lowercases one word CamelCase" do
|
7
|
+
expect(Nori::StringUtils.snakecase("Merb")).to eq("merb")
|
8
|
+
end
|
9
|
+
|
10
|
+
it "makes one underscore snakecase two word CamelCase" do
|
11
|
+
expect(Nori::StringUtils.snakecase("MerbCore")).to eq("merb_core")
|
12
|
+
end
|
13
|
+
|
14
|
+
it "handles CamelCase with more than 2 words" do
|
15
|
+
expect(Nori::StringUtils.snakecase("SoYouWantContributeToMerbCore")).to eq("so_you_want_contribute_to_merb_core")
|
16
|
+
end
|
17
|
+
|
18
|
+
it "handles CamelCase with more than 2 capital letter in a row" do
|
19
|
+
expect(Nori::StringUtils.snakecase("CNN")).to eq("cnn")
|
20
|
+
expect(Nori::StringUtils.snakecase("CNNNews")).to eq("cnn_news")
|
21
|
+
expect(Nori::StringUtils.snakecase("HeadlineCNNNews")).to eq("headline_cnn_news")
|
22
|
+
end
|
23
|
+
|
24
|
+
it "does NOT change one word lowercase" do
|
25
|
+
expect(Nori::StringUtils.snakecase("merb")).to eq("merb")
|
26
|
+
end
|
27
|
+
|
28
|
+
it "leaves snake_case as is" do
|
29
|
+
expect(Nori::StringUtils.snakecase("merb_core")).to eq("merb_core")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nori
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.7.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Harrington
|
@@ -10,22 +10,36 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2024-07-28 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: bigdecimal
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
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
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: '0'
|
15
29
|
- !ruby/object:Gem::Dependency
|
16
30
|
name: rake
|
17
31
|
requirement: !ruby/object:Gem::Requirement
|
18
32
|
requirements:
|
19
33
|
- - "~>"
|
20
34
|
- !ruby/object:Gem::Version
|
21
|
-
version:
|
35
|
+
version: 12.3.3
|
22
36
|
type: :development
|
23
37
|
prerelease: false
|
24
38
|
version_requirements: !ruby/object:Gem::Requirement
|
25
39
|
requirements:
|
26
40
|
- - "~>"
|
27
41
|
- !ruby/object:Gem::Version
|
28
|
-
version:
|
42
|
+
version: 12.3.3
|
29
43
|
- !ruby/object:Gem::Dependency
|
30
44
|
name: nokogiri
|
31
45
|
requirement: !ruby/object:Gem::Requirement
|
@@ -46,23 +60,25 @@ dependencies:
|
|
46
60
|
requirements:
|
47
61
|
- - "~>"
|
48
62
|
- !ruby/object:Gem::Version
|
49
|
-
version:
|
63
|
+
version: 3.11.0
|
50
64
|
type: :development
|
51
65
|
prerelease: false
|
52
66
|
version_requirements: !ruby/object:Gem::Requirement
|
53
67
|
requirements:
|
54
68
|
- - "~>"
|
55
69
|
- !ruby/object:Gem::Version
|
56
|
-
version:
|
70
|
+
version: 3.11.0
|
57
71
|
description: XML to Hash translator
|
58
72
|
email: me@rubiii.com
|
59
73
|
executables: []
|
60
74
|
extensions: []
|
61
75
|
extra_rdoc_files: []
|
62
76
|
files:
|
77
|
+
- ".devcontainer/devcontainer.json"
|
78
|
+
- ".github/dependabot.yml"
|
79
|
+
- ".github/workflows/test.yml"
|
63
80
|
- ".gitignore"
|
64
81
|
- ".rspec"
|
65
|
-
- ".travis.yml"
|
66
82
|
- CHANGELOG.md
|
67
83
|
- Gemfile
|
68
84
|
- LICENSE
|
@@ -73,25 +89,24 @@ files:
|
|
73
89
|
- lib/nori.rb
|
74
90
|
- lib/nori/core_ext.rb
|
75
91
|
- lib/nori/core_ext/hash.rb
|
76
|
-
- lib/nori/core_ext/object.rb
|
77
|
-
- lib/nori/core_ext/string.rb
|
78
92
|
- lib/nori/parser/nokogiri.rb
|
79
93
|
- lib/nori/parser/rexml.rb
|
80
94
|
- lib/nori/string_io_file.rb
|
95
|
+
- lib/nori/string_utils.rb
|
81
96
|
- lib/nori/string_with_attributes.rb
|
82
97
|
- lib/nori/version.rb
|
83
98
|
- lib/nori/xml_utility_node.rb
|
84
99
|
- nori.gemspec
|
85
100
|
- spec/nori/api_spec.rb
|
86
101
|
- spec/nori/core_ext/hash_spec.rb
|
87
|
-
- spec/nori/core_ext/object_spec.rb
|
88
|
-
- spec/nori/core_ext/string_spec.rb
|
89
102
|
- spec/nori/nori_spec.rb
|
103
|
+
- spec/nori/string_utils_spec.rb
|
90
104
|
- spec/spec_helper.rb
|
91
105
|
homepage: https://github.com/savonrb/nori
|
92
106
|
licenses:
|
93
107
|
- MIT
|
94
|
-
metadata:
|
108
|
+
metadata:
|
109
|
+
rubygems_mfa_required: 'true'
|
95
110
|
post_install_message:
|
96
111
|
rdoc_options: []
|
97
112
|
require_paths:
|
@@ -100,22 +115,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
100
115
|
requirements:
|
101
116
|
- - ">="
|
102
117
|
- !ruby/object:Gem::Version
|
103
|
-
version:
|
118
|
+
version: '3.0'
|
104
119
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
105
120
|
requirements:
|
106
121
|
- - ">="
|
107
122
|
- !ruby/object:Gem::Version
|
108
123
|
version: '0'
|
109
124
|
requirements: []
|
110
|
-
|
111
|
-
rubygems_version: 2.2.2
|
125
|
+
rubygems_version: 3.4.10
|
112
126
|
signing_key:
|
113
127
|
specification_version: 4
|
114
128
|
summary: XML to Hash translator
|
115
|
-
test_files:
|
116
|
-
- spec/nori/api_spec.rb
|
117
|
-
- spec/nori/core_ext/hash_spec.rb
|
118
|
-
- spec/nori/core_ext/object_spec.rb
|
119
|
-
- spec/nori/core_ext/string_spec.rb
|
120
|
-
- spec/nori/nori_spec.rb
|
121
|
-
- spec/spec_helper.rb
|
129
|
+
test_files: []
|
data/.travis.yml
DELETED
data/lib/nori/core_ext/object.rb
DELETED
data/lib/nori/core_ext/string.rb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
class Nori
|
2
|
-
module CoreExt
|
3
|
-
module String
|
4
|
-
|
5
|
-
# Returns the String in snake_case.
|
6
|
-
def snakecase
|
7
|
-
str = dup
|
8
|
-
str.gsub!(/::/, '/')
|
9
|
-
str.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
10
|
-
str.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
|
11
|
-
str.tr! ".", "_"
|
12
|
-
str.tr! "-", "_"
|
13
|
-
str.downcase!
|
14
|
-
str
|
15
|
-
end unless method_defined?(:snakecase)
|
16
|
-
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
String.send :include, Nori::CoreExt::String
|
@@ -1,19 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
describe Object do
|
4
|
-
|
5
|
-
describe "#blank?" do
|
6
|
-
[nil, false, [], {}].each do |object|
|
7
|
-
it "should return true for: #{object.inspect}" do
|
8
|
-
expect(object.blank?).to be_true
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
[true, [nil], 1, "string", { :key => "value" }].each do |object|
|
13
|
-
it "should return false for: #{object.inspect}" do
|
14
|
-
expect(object.blank?).to be_false
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
end
|
@@ -1,33 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
describe String do
|
4
|
-
|
5
|
-
describe "#snakecase" do
|
6
|
-
it "lowercases one word CamelCase" do
|
7
|
-
expect("Merb".snakecase).to eq("merb")
|
8
|
-
end
|
9
|
-
|
10
|
-
it "makes one underscore snakecase two word CamelCase" do
|
11
|
-
expect("MerbCore".snakecase).to eq("merb_core")
|
12
|
-
end
|
13
|
-
|
14
|
-
it "handles CamelCase with more than 2 words" do
|
15
|
-
expect("SoYouWantContributeToMerbCore".snakecase).to eq("so_you_want_contribute_to_merb_core")
|
16
|
-
end
|
17
|
-
|
18
|
-
it "handles CamelCase with more than 2 capital letter in a row" do
|
19
|
-
expect("CNN".snakecase).to eq("cnn")
|
20
|
-
expect("CNNNews".snakecase).to eq("cnn_news")
|
21
|
-
expect("HeadlineCNNNews".snakecase).to eq("headline_cnn_news")
|
22
|
-
end
|
23
|
-
|
24
|
-
it "does NOT change one word lowercase" do
|
25
|
-
expect("merb".snakecase).to eq("merb")
|
26
|
-
end
|
27
|
-
|
28
|
-
it "leaves snake_case as is" do
|
29
|
-
expect("merb_core".snakecase).to eq("merb_core")
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
end
|